{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "06a3bbec",
   "metadata": {},
   "source": [
    "下面用代码实现循环神经网络。首先读取数据，使用《小王子》这本书作为训练语料。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "316b323b",
   "metadata": {},
   "outputs": [],
   "source": [
    "from nltk.tokenize import sent_tokenize, word_tokenize\n",
    "from collections import defaultdict\n",
    "\n",
    "# 使用类管理数据对象，包括文本读取、文本预处理等\n",
    "class TheLittlePrinceDataset:\n",
    "    def __init__(self, tokenize=True):\n",
    "        # 利用NLTK函数进行分句和分词\n",
    "        text = open('the little prince.txt', 'r', encoding='utf-8').read()\n",
    "        if tokenize:\n",
    "            self.sentences = sent_tokenize(text.lower())\n",
    "            self.tokens = [word_tokenize(sent) for sent in self.sentences]\n",
    "        else:\n",
    "            self.text = text\n",
    "\n",
    "    def build_vocab(self, min_freq=1):\n",
    "        # 统计词频\n",
    "        frequency = defaultdict(int)\n",
    "        for sentence in self.tokens:\n",
    "            for token in sentence:\n",
    "                frequency[token] += 1\n",
    "        self.frequency = frequency\n",
    "\n",
    "        # 加入<unk>处理未登录词，加入<pad>用于对齐变长输入进而加速\n",
    "        self.token2id = {'<unk>': 1, '<pad>': 0}\n",
    "        self.id2token = {1: '<unk>', 0: '<pad>'}\n",
    "        for token, freq in sorted(frequency.items(), key=lambda x: -x[1]):\n",
    "            # 丢弃低频词\n",
    "            if freq > min_freq:\n",
    "                self.token2id[token] = len(self.token2id)\n",
    "                self.id2token[len(self.id2token)] = token\n",
    "            else:\n",
    "                break\n",
    "\n",
    "    def get_word_distribution(self):\n",
    "        distribution = np.zeros(vocab_size)\n",
    "        for token, freq in self.frequency.items():\n",
    "            if token in dataset.token2id:\n",
    "                distribution[dataset.token2id[token]] = freq\n",
    "            else:\n",
    "                # 不在词表中的词按<unk>计算\n",
    "                distribution[1] += freq\n",
    "        distribution /= distribution.sum()\n",
    "        return distribution\n",
    "\n",
    "    # 将分词结果转化为索引表示\n",
    "    def convert_tokens_to_ids(self, drop_single_word=True):\n",
    "        self.token_ids = []\n",
    "        for sentence in self.tokens:\n",
    "            token_ids = [self.token2id.get(token, 1) for token in sentence]\n",
    "            # 忽略只有一个token的序列，无法计算loss\n",
    "            if len(token_ids) == 1 and drop_single_word:\n",
    "                continue\n",
    "            self.token_ids.append(token_ids)\n",
    "        \n",
    "        return self.token_ids\n",
    "\n",
    "dataset = TheLittlePrinceDataset()\n",
    "dataset.build_vocab(min_freq=1)\n",
    "sentences = dataset.convert_tokens_to_ids()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "58df11c1",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "115\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import os\n",
    "import sys\n",
    "\n",
    "# 导入前面实现的小王子数据集\n",
    "sys.path.append('./code')\n",
    "from utils import TheLittlePrinceDataset\n",
    "\n",
    "dataset = TheLittlePrinceDataset()\n",
    "\n",
    "# 统计每句话的长度\n",
    "sent_lens = []\n",
    "max_len = -1\n",
    "for sentence in dataset.tokens:\n",
    "    sent_len = len(sentence)\n",
    "    sent_lens.append(sent_len)\n",
    "    if sent_len > max_len:\n",
    "        max_len = sent_len\n",
    "        longest = sentence\n",
    "print(max_len)\n",
    "\n",
    "# 简单看一下语料中序列长度的分布\n",
    "import matplotlib.pyplot as plt\n",
    "plt.hist(sent_lens, bins=20)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf1e69d9",
   "metadata": {},
   "source": [
    "接下来建立词表，截断过长的序列，将序列填充（padding）到相同长度。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "f25456ee",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1089 115\n",
      "(1088, 40)\n",
      "[  4  16  19 733 734 735 733 734 735   2  63  20   9   1   1   2   1  10\n",
      " 736 737   4  16  19  21   1   2  30 371 209  33 294   3   0   0   0   0\n",
      "   0   0   0   0]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "dataset.build_vocab()\n",
    "sent_tokens = dataset.convert_tokens_to_ids()\n",
    "# 截断和填充\n",
    "max_len=40\n",
    "for i, tokens in enumerate(sent_tokens):\n",
    "    tokens = tokens[:max_len]\n",
    "    tokens += [dataset.token2id['<pad>']] * (max_len - len(tokens))\n",
    "    sent_tokens[i] = tokens\n",
    "sent_tokens = np.array(sent_tokens)\n",
    "\n",
    "print(len(dataset.tokens), max([len(x) for x in dataset.tokens]))\n",
    "print(sent_tokens.shape)\n",
    "print(sent_tokens[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "06e6fb52",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "import torch\n",
    "from torch import nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "# 定义一个正态分布的函数用于初始化参数\n",
    "def normal(shape):\n",
    "    return torch.randn(size=shape) * 0.01\n",
    "\n",
    "class RNN(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size):\n",
    "        super(RNN, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        # 将输入与隐状态分别经过线性变化后相加\n",
    "        self.W_xh = nn.Parameter(normal((input_size, hidden_size)))\n",
    "        self.W_hh = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_h = nn.Parameter(torch.zeros(hidden_size))\n",
    "    \n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((batch_size, hidden_size), dtype=torch.float),)\n",
    "    \n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        hidden_state, = states\n",
    "        hiddens = []\n",
    "        for step in range(seq_len):\n",
    "            # 输入hidden_state与inputs经过线性变换后相加，\n",
    "            # 输出的hidden_state也是下一时刻输入的hidden_state\n",
    "            xh = torch.mm(inputs[step], self.W_xh)\n",
    "            hh = torch.mm(hidden_state, self.W_hh)\n",
    "            hidden_state = xh + hh + self.b_h\n",
    "            hidden_state = torch.tanh(hidden_state)\n",
    "            hiddens.append(hidden_state)\n",
    "        # 返回所有时刻的hidden_state: seq_len * batch_size * hidden_size\n",
    "        # 以及最后时刻的hidden_state（可能用于后续输入）: \n",
    "        # batch_size * hidden_size\n",
    "        return torch.stack(hiddens, dim=0), (hidden_state,)\n",
    "\n",
    "# 在循环神经网络的基础上添加语言模型的输入输出、损失计算等\n",
    "class RNNLM(nn.Module):\n",
    "    def __init__(self, model, vocab_size, hidden_size):\n",
    "        super(RNNLM, self).__init__()\n",
    "        self.vocab_size = vocab_size\n",
    "        self.hidden_size = hidden_size\n",
    "        self.embedding = nn.Embedding(vocab_size, hidden_size)\n",
    "        self.model = model\n",
    "        self.W_hq = nn.Parameter(normal((hidden_size, vocab_size)))\n",
    "        self.b_q = nn.Parameter(torch.zeros(vocab_size))\n",
    "        \n",
    "    def forward(self, input_ids):\n",
    "        batch_size, seq_len = input_ids.shape\n",
    "        # input_ids形状为batch_size * seq_len，翻转为seq_len * batch_size，\n",
    "        # 将seq_len放在第一维方便计算\n",
    "        input_ids = torch.permute(input_ids, (1, 0))\n",
    "        # seq_len * batch_size * embed_size\n",
    "        embed = self.embedding(input_ids)\n",
    "        # batch_size * hidden_size\n",
    "        states = self.model.init_rnn_state(batch_size, self.hidden_size)\n",
    "        hiddens, _ = self.model(embed, states)\n",
    "    \n",
    "        hiddens = torch.flatten(hiddens[:-1], start_dim=0, end_dim=1)\n",
    "        output_states = torch.mm(hiddens, self.W_hq) + self.b_q\n",
    "        labels = torch.flatten(input_ids[1:], start_dim=0, end_dim=1)\n",
    "        loss_fct = nn.CrossEntropyLoss(ignore_index=0)\n",
    "        loss = loss_fct(output_states, labels)\n",
    "        return loss"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "45a010aa",
   "metadata": {},
   "source": [
    "下面展示使用梯度裁剪的循环神经网络语言模型的训练代码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "760da2e1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1088, 40)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=0.3508: 100%|█| 200/200 [06:58<00:00,  2.09s\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAioAAAGwCAYAAACHJU4LAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAABaZ0lEQVR4nO3dd3RUdd4G8OfOTDLpM+k9pBJaEjqELiBNEVlsyK66axdFRV2WLbbdFVZdrLzo7qq46gpWVBCRGqS3hN4SEtJ7mfRJZu77x8zcZEhIQpjkTpLnc07Oydy5M/leLmQeflUQRVEEERERkR1SyF0AERER0dUwqBAREZHdYlAhIiIiu8WgQkRERHaLQYWIiIjsFoMKERER2S0GFSIiIrJbKrkLuB5GoxG5ublwd3eHIAhyl0NEREQdIIoiKisrERQUBIWi7TaTHh1UcnNzERoaKncZRERE1AlZWVkICQlp85weHVTc3d0BmC7Uw8ND5mqIiIioI3Q6HUJDQ6XP8bb06KBi6e7x8PBgUCEiIuphOjJsg4NpiYiIyG4xqBAREZHdYlAhIiIiu8WgQkRERHaLQYWIiIjsFoMKERER2S0GFSIiIrJbDCpERERktxhUiIiIyG4xqBAREZHdYlAhIiIiu8WgQkRERHaLQaUd9Y0GGIyi3GUQERH1SQwqbcgpr8XU15Mwb/UeiCLDChERUXdTyV2AvaprMODRT48ip7wWOeW1qKpvhLuTg9xlERER9SlsUbmKF78/jRPZFdLj0mq9jNUQERH1TQwqrVh3KBPrDmdBEAC1yvRHxKBCRETU/RhUWtE/wB3+Hmo8c2N/xPi7AQDKahhUiIiIuhvHqLRieJgnfnpyEjTODjiUUQYAKKliUCEiIupuDCpX4enqCADwcjENoGWLChERUfdj1087vFzVAIDS6gaZKyEiIup7GFTa4eVqalEpra6XuRIiIqK+R9ag8uKLL0IQBKuvAQMGyFlSC5YuILaoEBERdT/Zx6gMHjwY27Ztkx6rVLKXZMVbCipsUSEiIupusqcClUqFgIAAucu4Kk8XU1Apq2GLChERUXeTfYzKxYsXERQUhMjISCxatAiZmZlXPbe+vh46nc7qq6t5u1laVDjrh4iIqLvJGlTGjBmDtWvX4qeffsKaNWuQnp6OiRMnorKystXzV6xYAY1GI32FhoZ2eY2WFpWK2gY0GIxd/vOIiIioiSDa0bbA5eXl6NevH1atWoX777+/xfP19fWor28aK6LT6RAaGoqKigp4eHh0SU0Go4joP/0IUQQO/2k6fN3VXfJziIiI+gqdTgeNRtOhz2/Zx6g0p9Vq0b9/f6Smprb6vFqthlrdvUFBqRCgdXZAWU0DSqv1DCpERETdSPYxKs1VVVUhLS0NgYGBcpdipWmKMsepEBERdSdZg8qzzz6LpKQkZGRkYN++fZg/fz6USiUWLlwoZ1ktWKYocxl9IiKi7iVr1092djYWLlyIkpIS+Pr6YsKECThw4AB8fX3lLKsFy4DaEraoEBERdStZg8q6devk/PEdZpmiXMagQkRE1K3saoyKvbK0qHCMChERUfdiUOkALw6mJSIikgWDSgd4cTAtERGRLBhUOsAyPbmkikGFiIioOzGodACnJxMREcmDQaUDmg+mtaMdB4iIiHo9BpUOsExPrm80okZvkLkaIiKivoNBpQOcHZRQq0x/VJz5Q0RE1H0YVDpAEARpnAqDChERUfdhUOkgy67JueW1MldCRETUdzCodNDAQA8AwOlcncyVEBER9R0MKh00OFgDADiVWyFzJURERH0Hg0oHDQkytaicyqngFGUiIqJuwqDSQQMDPaBUCCiu0qOwsl7ucoiIiPoEBpUOcnJQItrXDQBwMpvdP0RERN2BQeUaDA42d/9wnAoREVG3YFC5BkOCzANqczjzh4iIqDswqFyDIeaZP6fZokJERNQtGFSuwSDzzJ+8ijoUV3FALRERUVdjULkGbmoVIn1cAXDhNyIiou7AoHKNLN0/x7PK5S2EiIioD2BQuUbjorwBABtScrjwGxERURdjULlGNycEwcVRiUtF1TicUSZ3OURERL0ag8o1clOrMDc+CACw7lCmzNUQERH1bgwqnXDX6FAAwKaTeaioaZC5GiIiot6LQaUThoZqMSDAHfWNRmxIyZG7HCIiol6LQaUTBEHAXaNMrSobT+TKXA0REVHvxaDSScPCPAEAOWW1MldCRETUezGodJKvuxoAUFRVz2nKREREXYRBpZN83ExBpcEgopwDaomIiLoEg0onOaoU8HRxAAAUVnLfHyIioq7AoHIdpO4fBhUiIqIuwaByHZrGqdTJXAkREVHvxKByHfzcnQAAhTq2qBAREXUFBpXrwK4fIiKirsWgch18zTN/OJiWiIioazCoXAc/D7aoEBERdSUGletgaVEpqmJQISIi6goMKtfB0qJSqOOsHyIioq7AoHIdfN1Ms350dY2oazDIXA0REVHvw6ByHTycVXBUmf4IOU6FiIjI9hhUroMgCBynQkRE1IUYVK4T11IhIiLqOgwq18kSVLiWChERke0xqFwnP7aoEBERdRkGlevU1PXDKcpERES2xqBynThGhYiIqOswqFwnyw7KDCpERES2x6BynTiYloiIqOswqFwnS1AprqqH0SjKXA0REVHvwqBynXzd1BAEoMEgoqRaL3c5REREvQqDynVyVCkQ4ukMAEgrqpK5GiIiot6FQcUGon3dAACphQwqREREtsSgYgPRfgwqREREXYFBxQYsQYVdP0RERLbFoGIDbFEhIiLqGgwqNhDt6w4AyKuoQ1V9o8zVEBER9R4MKjagcXGAj5tpPZU0tqoQERHZjN0ElZUrV0IQBDz11FNyl9Ip0X6uANj9Q0REZEt2EVQOHz6M999/H/Hx8XKX0mnSOBUOqCUiIrIZ2YNKVVUVFi1ahH//+9/w9PSUu5xO41oqREREtid7UFm8eDFuuukmTJ8+vd1z6+vrodPprL7sRbSfaUBtWmEVfjqVj4mv7sDmk3kyV0VERNSzyRpU1q1bh2PHjmHFihUdOn/FihXQaDTSV2hoaBdX2HGWrp+MkmosWZeMrNJafLw/Q96iiIiIejjZgkpWVhaefPJJfPbZZ3BycurQa5YvX46KigrpKysrq4ur7Dh/DzXc1CoYRUDfaAQAHLtcjlq9QebKiIiIei7ZgsrRo0dRWFiI4cOHQ6VSQaVSISkpCW+//TZUKhUMhpYf8Gq1Gh4eHlZf9kIQBPT3N7WqjOjniUCNE/QGI45cLpW5MiIiop5LtqAybdo0nDx5EikpKdLXyJEjsWjRIqSkpECpVMpVWqctnzMQD0yIwAf3jsT4aB8AwJ7UYpmrIiIi6rlUcv1gd3d3DBkyxOqYq6srvL29WxzvKUaFe2FUuBcAYHy0N746mo19qSUyV0VERNRzyT7rp7caF2VqUTmVW4HyGr3M1RAREfVMsrWotGbXrl1yl2Az/h5OiPFzw8XCKuxPK8HsuEC5SyIiIupx2KLShSzjVPamcZwKERFRZzCodKFxUd4AgEPpnPlDRETUGQwqXSjCx7RRYWFlvcyVEBER9UwMKl1I4+IAAKiobYDRKMpcDRERUc/DoNKFtM6OAABRBHR1DTJXQ0RE1PMwqHQhR5UCro6mhevKahhUiIiIrhWDShfTuphaVbiWChER0bVjUOliWvM4lXK2qBAREV0zBpUu5mlpUalliwoREdG1YlDpYpaZP2XVbFEhIiK6VgwqXczT0vVTawoqP53Kx+3v7UNWaY2cZREREfUIDCpdzDJF2TKY9rODl3E4oww/ncqXsywiIqIegUGli105mLZAVwcAyC5jiwoREVF7GFS6mGV6cpm5RSW/whJUamWriYiIqKdgUOlins2W0a/VG6CrawQAZLFFhYiIqF0MKl3M0vVTVqOXun0AU4uKKHL/HyIiorYwqHSxppVpG6yCSo3egNJqrq1CRETUFgaVLqZ1NrWoVNY1IqfcelwKx6kQERG1jUGli2nMQQUALhRUWT3HoEJERNQ2BpUuplIq4O6kAgCcz9dZPccBtURERG1jUOkGlgG15/MrAQDualNw4VoqREREbWNQ6QaWjQlzzWuoDA3TAgCyStn1Q0RE1BYGlW7QfJwKAIzs5wXAukWlvtGAvanFOJxR2q21ERER2TOV3AX0BZYWFYuR4Z4ATINp9Y1GvPD9KWxIzkVtgwGCAGx5ahL6+7vLUSoREZFdYYtKN7CMUbEYGqqFQgDqG434z55L+PxQlhRSRBH45WKxTJUSERHZFwaVbqBt1qLi6eIAV7UKgRpnAMA721MBAEtv7I/nZsYCAA6ll3R/kURERHaIQaUbaJuNUfH3cAIABHuagkptgwEeTir8bkIExkR4AwAOpZdyeX0iIiIwqHQLT9eWQSXU00U6dt/4CLipVYgL1sDJQYGymgZcLKxq8T5ERER9DYNKN9A6N3X9+HuoAQChXqYWFRdHJX47LhwA4KhSYEQ/00Dbg+mc/UNERMSg0g2aD6YNMLeo3BDrB7VKgSXTYuDp2hRkRoc3df8QERH1dZye3A2aD6b1MweVhFAtzr48CwqFYHXu6AjTGiuH0ksgiiIEwfp5IiKivoQtKt3As5UWFQAtQgoADAvTwlGpQIGuHpdLuMQ+ERH1bQwq3cDdyQGWhhH/ZkGlNU4OSiSEagCw+4eIiIhBpRsoFQJGhXvB30ONKD/Xds+PD9ECAC4UVHZxZURERPaNY1S6yecPjkWj0Qi1StnuuZG+pjBzqbi6q8siIiKyawwq3USpEKBUtB9SACDCxxRU0hlUiIioj2PXjx2K9HEDAGSW1qDBYJS5GiIiIvkwqNghfw81nB2UMBhFZJVy5g8REfVdDCp2SBAEdv8QERGBQcVuRfgyqBARETGo2KlIH878ISIiYlCxU9IU5SLuokxERH0Xg4qdijDP/GHXDxER9WUMKnYqwtvUolKgq0d1faPM1RAREcmDQcVOaVwc4O1q2nWZrSpERNRXMajYMU5RJiKivo5BxY4xqBARUV/HoGLHLGuppBZy5g8REfVNDCp2LD5YCwDYcjofOeW18hZDREQkAwYVOzY+2hujw71Q32jEPzafQ12DAc9+eRw3rkpCabVeOm/3hSL8cDwXSReKUKirk7FiIiIi21LJXQBdnSAIeH7uIMx9dw++P56L1MIqnMnTAQD2p5XgpvhAHMkoxT0fHpJeo3VxQNJzN0Dj7CBX2URERDbDFhU7NyRYgztGhAKAFFIAIKPENMD2eHYFAMDb1REeTiqU1zRgQ3JO9xdKRETUBRhUeoBnZ8YiwMMJ/h5q3BwfCAC4VGQKKunFpoG2d44KxTMzYgEAnx64DFEU5SmWiIjIhhhUegBfdzV2PDsZe5dNxczBAQCaWlQsgSXS1w3zhwfD2UGJi4VVOJxRJlu9REREtsKg0kO4OKqgUiqktVUyiq2DSoSPKzycHDBvaBAA4LODl+UplIiIyIYYVHqYcHNQKanWI7+iDvnmWT5R5jVXFo3pBwDYfDIfJVX18hRJRERkIwwqPYybWgVfdzUAYOf5QgCAl6sjtC6mfYHiQjQYEOAOvcGIg+mlstVJRERkCwwqPZBlZ+XtZwsAAJHmVhaLEE8XAEBFbUP3FkZERGRjDCo9kGWcyp7UYqvHFh7OpuVxdAwqRETUw8kaVNasWYP4+Hh4eHjAw8MDiYmJ2Lx5s5wl9QiWcSp1DUYAphk/zXk4mRZ709UxqBARUc8ma1AJCQnBypUrcfToURw5cgRTp07FvHnzcPr0aTnLsnsRPi5WjyN9r2xRMQeV2sZuq4mIiKgryLqE/ty5c60e//3vf8eaNWtw4MABDB48uMX59fX1qK9vmsmi0+lanNMXRPhYt6BcOUbFw8nc9cMWFSIi6uHsZoyKwWDAunXrUF1djcTExFbPWbFiBTQajfQVGhrazVXah37eTS0qCgEI87ZuYWlqUWFQISKink32oHLy5Em4ublBrVbjkUcewbfffotBgwa1eu7y5ctRUVEhfWVlZXVztfbByUGJII0TACDUywVqldLq+aYxKuz6ISKink323ZNjY2ORkpKCiooKfPXVV7j33nuRlJTUalhRq9VQq9UyVGl/InxdkVtR16LbB+CsHyIi6j1kb1FxdHREdHQ0RowYgRUrViAhIQFvvfWW3GXZvSjzTJ+oK2b8AJz1Q0REvYfsLSpXMhqNVgNmqXX3T4iAAOC+8eEtntO0Mevngz3pKK6qx+9nxkIQhC6ukoiI6PrIGlSWL1+O2bNnIywsDJWVlfjf//6HXbt2YcuWLXKW1SP083bFS/OGtPqcpUWltsEAfaMRjipTw1lmSQ3+uvEMAGDhqLAWg3CJiIjsjaxBpbCwEPfccw/y8vKg0WgQHx+PLVu24MYbb5SzrB7PzanptlbWNcDbzTSu56tj2dLxkup6BhUiIrJ7sgaVDz74QM4f32spFQLc1SpU1jdCV9cIbzc1jEYRXx9tCirlNRy/QkRE9k/2wbTUNSxrqVg2JtyXVoKc8lrp+dJqvSx1ERERXYtOBZWPP/4YmzZtkh7//ve/h1arxbhx43D58mWbFUed5+5kPUX5y6PWa86U1TCoEBGR/etUUHnllVfg7OwMANi/fz9Wr16NV199FT4+Pnj66adtWiB1jrQ6bV0DdHUN+OlUPgBgaKgWALt+iIioZ+jUGJWsrCxER0cDADZs2IAFCxbgoYcewvjx4zFlyhRb1ked1HyK8vGsctQ3GhHm5YLJ/X2RklWOUraoEBFRD9CpFhU3NzeUlJQAAH7++Wdplo6TkxNqa2vbeil1k+aLvuWax6ZE+rrCy9URAFDOoEJERD1Ap1pUbrzxRjzwwAMYNmwYLly4gDlz5gAATp8+jfDwcFvWR53UfBn9Gr0BABCkdYbWxRRgyqrZ9UNERPavUy0qq1evRmJiIoqKivD111/D29sbAHD06FEsXLjQpgVS57TWohKsdZZaVDiYloiIeoJOtahotVq8++67LY6/9NJL110Q2YZHszEqxVWmLQmCtE7wdGFQISKinqNTLSo//fQT9uzZIz1evXo1hg4dirvvvhtlZWU2K446z8MyPblZi0qQplnXT00DRFGUrT4iIqKO6FRQee6556DT6QAAJ0+exDPPPIM5c+YgPT0dS5cutWmB1DmWFpXymgbkVtQBMI1RsXT96BuN0tgVIiIie9Wprp/09HQMGjQIAPD111/j5ptvxiuvvIJjx45JA2tJXpYxKunF1dA3GiEIQIDGCSqFAEeVAvpGI8pq9HBV290G2kRERJJOtag4OjqipqYGALBt2zbMmDEDAODl5SW1tJC8LLN+LEvo+7s7wUGpgCAI8HRpam0hIiKyZ5367/SECROwdOlSjB8/HocOHcL69esBABcuXEBISIhNC6TOsbSoWAR7Okvfe7o4okBXz/1+iIjI7nWqReXdd9+FSqXCV199hTVr1iA4OBgAsHnzZsyaNcumBVLnWMaoWARprYMKwJk/RERk/zrVohIWFoaNGze2OP7GG29cd0FkG+5qFQQBsEzsCdI6Sc95urLrh4iIeoZOj6Q0GAzYsGEDzp49CwAYPHgwbrnlFiiVSpsVR52nUAhwU6tQWdcIwLTYm4XW3KLCrh8iIrJ3nQoqqampmDNnDnJychAbGwsAWLFiBUJDQ7Fp0yZERUXZtEjqHA8nBymoBGmagoqXS9v7/aRkleNcng43JwTBjbOCiIhIRp0ao7JkyRJERUUhKysLx44dw7Fjx5CZmYmIiAgsWbLE1jVSJzUfpxJk1aLStOjblURRxEP/PYI/fHMSk17dif/8cgkGIxeGIyIieXTqv8tJSUk4cOAAvLy8pGPe3t5YuXIlxo8fb7Pi6PpYVqcFrLt+2hpMm11Wi8JK05L7pdV6/G3TWbiqVVg4OqyLqyUiImqpUy0qarUalZWVLY5XVVXB0dHxuosi27C0qLg6KqV1VQBYbUx4Irsco/++DV8cyQIAnMypAAAMCvTAguGmqeZncluujfP98Vz88duT0Dcau/QaiIiob+tUULn55pvx0EMP4eDBgxBFEaIo4sCBA3jkkUdwyy232LpG6iTLWipBWmcIgiAdl7p+qhuwdl8GCivrsXZvBgDgRLYpqAwN02JspKnFLL242up9RVHEyz+cxv8OZmLHucKuvgwiIurDOhVU3n77bURFRSExMRFOTk5wcnLCuHHjEB0djTfffNPGJVJnWVpRmo9PAZq6fkqq67H9rClonMnTobRaj5M55QCAuGANIn1dAbQMKtlltSiuMnUbWc4nIiLqCp0ao6LVavHdd98hNTVVmp48cOBAREdH27Q4uj5+7qa1UyJ8XK2Oe5q7fuoajKhraOq62ZdWjJPmFpW4YI0UcHLKa1GrN8DZ0TT1PDmrXHqNpQWGiIioK3Q4qLS3K/LOnTul71etWtX5ishmFo4OhUIA5g0Ntjru4aSCUiFIs3ksC8OtO5QFXV0jHFUK9Pd3h6NKAa2LA8prGpBRUo2BgR4AgJTMcum9TuZUQBRFZJfV4s739+O2kaFYemP/brtGIiLq3TocVJKTkzt0XvOxECQvrYsjHp7cck0bQRCgdXZAiXnBt7tGheLzQ1nYk1oMABgY6AFHlalXMMLHFcmZ5UgvbgoqyVll0nuV1zQgu6wWXx7JQm5FHTYk5zCoEBGRzXQ4qDRvMaGeT+tiCirODkosvTEWXxzJllpY4oI9pPMsQeVSURUAQN9oxGnzLCAfN0cUV+lxPLscP58pAABkl9VA32iUgg4REdH14KdJH2WZojypvw983dWID9FIz8UHa6Xvo3zdAACXzANqz+bpoG80wtPFATMGBwAANp/Mx7l803R1o2gKK0RERLbAoNJHWbpxfmVeK2V8lI/0XFyz0GIZiGuZ+ZNiHkibEKpFgvm8TSfzrN47o8R6lhAREVFnMaj0UX+YPQCbn5yImeZWkXHR3gAAJwcFYvzcpPOuDCrJmabxKUNDtYgP0Vq9p8I8PCm9mC0qRERkG9xxro9ycVRJrSoAMDbCG49NiUKkrxtUyqb8Gu5tCirlNQ0ordZLLSrDwjwR4+cGtUqBevPqtLOHBGLTyTxkFLNFhYiIbIMtKgQAUCgE/H7WANw2IsTquLOjUtonaOOJXGSUmFpLhoZooVIqMDjIFHZi/Nwwub8vAHb9EBGR7TCoULss3T8v/XAGADBrcAA05mX4E6NMXUY3xQein7cLAAYVIiKyHXb9ULsifFyxJ7UYBqOIQI0TVvwqTnru8RtiEB+ixdQBfigzr8uSU1bLKcpERGQT/CShdln2/FEqBLy9cJi0BD9g6hqaOTgADkoFfN3VcHVUwigCmaUcUEtERNePQYXaNXtIIEb088Qr84dgVLjXVc8TBAH9zINvOaCWiIhsgV0/1K4AjRO+fnRch86N8HHFmTwdx6kQEZFNsEWFbCrcxzSgNp0tKkREZAMMKmRTlnVXLpdwjAoREV0/BhWyqStXsiUiIroeDCpkU+HmoJJbUYv6RoPM1RARUU/HoEI25e3qCGcHJUQRyCuvk7scIiLq4RhUyKYEQUCwp2nJ/dzyWpmrISKino5BhWwuyLw3UDaDChERXScGFbK5YK0TALaoEBHR9WNQIZuz7LacU8agQkRE14dBhWzO0vWTW8GgQkRE14dBhWzuyhaV0mo9Vvx4FnnNgktOeS0uFVXJUh8REfUcDCpkc00tKnUwGkW8n5SG93dfwoofzwEA9I1GzF+9FzPf3I1TORVylkpERHaOQYVsLkDjBIVgCiTF1fVIySoHACRdKEKjwYjDGaUorKxHg0HE7786gQaDUd6CiYjIbjGokM05KBXw9zDN/Mkuq8XpXB0AoKK2ASlZ5dh2tkA690yeDv/afUmWOomIyP4xqFCXsHT/7E8rQVV9o3R8x7lCKajcFB8IAHhr20WOVyEiolYxqFCXsAyo/elUPgBAIZiOrzuchazSWqhVCrx2Wzwm9feF3mDEf/aky1UqERHZMQYV6hKWFpWT5sGys+MCIQimGUAAMD7aBy6OKjw6OQoAsCE5B7q6BnmKJSIiu8WgQl3Cst+PxeQYXwwN1UqPpw/0BwCMjfRCf3831OgN+PpodneWSEREPQCDCnUJyzL6FkOCNZga6yc9njbQ9L0gCPjN2H4AgE/2X4bRKHZfkUREZPcYVKhLBGtdpO8dVQrE+LthTnwg1CoFJvf3lWYFAcD84SFwU6twqbgae9OK5SiXiIjsFIMKdYmgZi0qAwPc4aBUIMrXDXuWTcV7vx5hda6bWoUFw4MBABuSc7u1TiIism8MKtQl3J0c4O6kAmDq9rHwdVfD2VHZ4vyxkd4AgFROUyYiomZkDSorVqzAqFGj4O7uDj8/P9x66604f/68nCWRDVmmKMc1CypXE+HrCgBIL6qCKHKcChERmcgaVJKSkrB48WIcOHAAW7duRUNDA2bMmIHq6mo5yyIbeXhyJCb198XsIYHtnhvubQoqurpGlNVwmjIREZmo5PzhP/30k9XjtWvXws/PD0ePHsWkSZNkqopsZf6wEMwfFtKhc50clAjWOiOnvBbpxVXwcvXq4uqIiKgnsKsxKhUVpsXBvLxa/5Cqr6+HTqez+qLeI8LH1KpyqYgtakREZGI3QcVoNOKpp57C+PHjMWTIkFbPWbFiBTQajfQVGhrazVVSV7IElfRiBhUiIjKxm6CyePFinDp1CuvWrbvqOcuXL0dFRYX0lZWV1Y0VUlcLZ1AhIqIryDpGxeLxxx/Hxo0bsXv3boSEXH1Mg1qthlqt7sbKqDtFMqgQEdEVZA0qoijiiSeewLfffotdu3YhIiJCznJIZs27foxGEXqDEQajCFe1XeRpIiKSgaxdP4sXL8ann36K//3vf3B3d0d+fj7y8/NRW1srZ1kkkxBPZ6gUAuobjcitqMXCfx/AuJU7UFxVL3dpREQkE1mDypo1a1BRUYEpU6YgMDBQ+lq/fr2cZZFMVEoFwrxNewR9uCcDyZnlqKhtwC8XiwAABbo63PPhIfx8Ol/OMomIqBvJ3vVD1FykjysuFVXj4/0Z0rH9aSWYPywEn+y/jN0XilBUWY8ZgwPkK5KIiLqN3cz6IQKaxqkYjE0h9sClUgDAjnOFAICzeTqUVuu7vzgiIup2DCpkVyJ83KTvpw/0g1IhILO0Bkcvl+FMXtMCfwculchRHhERdTMGFbIrlhYVAHhyWn9p5+WVm89anbcvrbhb6yIiInkwqJBdGRamxch+nrh7TBjiQjQYG2naTuFwRhkAID7EFFz2p7FFhYioL2BQIbvi5KDEV4+Owyvz4wAAiZHeVs//YfYACAKQVlSNAl2ddLxQV4d3d1xERS13XiYi6k0YVMiujQz3glIhAAACPJyQGOmNIUEtW1We/iIFr/98AWt2pclSJxERdQ0GFbJrbmoV4szjVG4Y4AtBEJAYZWplsYxT2ZdWjL2pptCyv9nYldJqPcprODuIiKgnY1Ahu/fAxAhE+7nh3nHhACAFlR3nipBZUoNVP1+Qzj2Vq0NlXQOq6xsx+63duOntPWgwGOUom4iIbICbqJDduzk+CDfHB0mPx0Z4I1jrjJzyWsx6azdq9AaoVQp4ODugqLIeRy6XobKuEQU609L7l0uqEe3nLlf5RER0HdiiQj2Os6MSXz2aiIQQDWr0BgDAPYn9MKW/LwDg4KVS/HgiTzr/YkGVLHUSEdH1Y1ChHilQ44z1Dyfit+PDMSXWF49NicZY8wyhnecKsfN8oXRuaiGDChFRT8WuH+qxnByUeGHuYOnxGPOaK+cLKq3Ou8igQkTUY7FFhXqNEE8XhHg6S48HBJjGpbBFhYio52JQoV5lbLMF4pZMiwEApBVVWW1ySEREPQe7fqhXSYz0xldHsxHu7YKZgwPgqFKgvtGI7LIaKAQB//z5PMpqGqBvNOKu0aGYNzTY6vX1jQZ8cTgLs+MC4eOmlukqiIjIgkGFepVbhgYhs7QGk2N9oVQIiPRxxbn8SqQWVmHTiTxsSMmVzs0srWkRVD49kIm/bjyDY5nleOPOod1cPRERXYldP9SrOCgVePrG/hge5gkAiPE3jVM5kV2BLafzATR1CeWU16JG32j1+hPZ5QCAvanFEEV2FxERyY1BhXq1aF83AMAnBy6jWm9AqJcznp4eA08XBwDApaJqq/PP5ZlmDBVW1iOjpKZ7iyUiohYYVKhXi/E3BZXSatOeP/MSgiEIAqLMASatqGlGkL7RaPX4UHoJiIhIXgwq1KvF+LlZPb51mGkp/mg/S1BpalG5VFyFxmazgw5eKu2GComIqC0MKtSr9fN2hVIhAAAGB3lIe/601qJyPt/U7aNWmf5ZHExnUCEikhuDCvVqjioFwr1dAAC3NpvhE+XnCgBIa7YY3DlzULkpLhAqhYCc8lpkl3GcChGRnBhUqNd7dkYs5g8Lxl2jQ6VjlhaV9OJqaTE4S4vKsDAt4kI0ANj9Q0QkN66jQr3e7LhAzI4LtDoW4ukCR6VpMbjc8lqEerlIQSU2wAOjI2qRnFmOTSfz4KpWIczLBYOCPOQon4ioT2OLCvVJSoWACB9T909qURV0dQ3IKa8FAMT6u2NshGkp/h3nCvHIp0dxy7t7pOeJiKj7MKhQn9V8nMoFc2tKoMYJGhcHjI/2wU3xgRgS7AGNswMajSL2pRbLWS4RUZ/EoEJ9VrRv0xTlc1K3j2lWkKNKgdV3D8fGJyZi4egwAMDhDI5XISLqbgwq1GdFWdZSKazC0ctlAJqCSnOjI0zL8R/OKOu+4oiICAAH01IfZpn5cyijFMgwHRth3iOouRFhXhAE0wyhosp6+LpzV2Uiou7CFhXqsyyDaQHTIm/PzYzFjYP8W5yncXFArHlzwyPs/iEi6lZsUaE+y1WtwpPTYpBdVounpscg1MvlqueOCvfCufxKHMoobTHVmYiIug6DCvVpT9/Yv0PnjQz3xCcHLuMIx6kQEXUrdv0QdcDoCC8AwOncClTVN8pcDRFR38GgQtQBgRpnhHg6wyhymjIRUXdiUCHqoAnRPgCAl384g4raBtQ3GvDv3Zew8URui3OzSmvw8CdH8OPJvO4uk4ioV+EYFaIOenZmLHZfKEJ6cTUe++woyqobcCZPBwBwVCowY3AAAKC4qh73fHgI6cXVuFxSgzkcfEtE1GlsUSHqIB83Nd7/zUioVQrsTS3BmTwdVAoBALD0i+NIK6pCdlkNfvvRYaQXVwMA0oqqoG80ylk2EVGPxhYVomsQF6LBa7cn4NkvjmN0hBf+cVs8nl6XYpq2/NYvUijxdnVEXYMB1XoD0oqqMDDQA5tP5uGLI1nwdVejn7crFo0Jg9bFUeYrIiKybwwqRNfoloQg3DjQH86OSgDAu4uGYe47e1Cgq4dSIWBoqBYvzxuMl74/g0MZpTiXr8PAQA/8bdNZqx2Yc8tr8ff5cXJdBhFRj8CgQtQJlpACAH7uTvhu8QSkFlYhIVQDdycHAMCAQHdTUMmrRE5ELXLKa6FUCPj1mDB8vP8yNp3MwwtzB8NRxR5YIqKr4W9IIhsI0DhhQoyPFFIAYECABwDgTJ4Oh9NNU5qHBHng+bmD4eOmRnlNA/akFslSLxFRT8GgQtRFBgaa9geyLL0PmJbiVyoE3Bxvmgn0XUrLqc1ERNSEQYWoi/T3d4cgAEWV9dh2pgBA0wq384YGAQB+Pl2AGj1XuiUiuhoGFaIu4qpWoZ95o8PCynoAphYVABgaqkWYlwtqGwzYdrZQthqJiOwdgwpRF7KMUwGAGD83eLqapiMLgoBbEkytKl8fzZalNiKinoBBhagLDQxsCiqjzN0+Fr8aHgyFACRdKMK+tOLuLo2IqEdgUCHqQgPMA2oBYHS4dVCJ9HXDr8f2A2DaP6jRwBVsiYiuxKBC1IUGNuv6GX1FiwoALL2xP7QuDjiXX4nPD2V2Z2lERD0CgwpRFwr1csbDkyPxxNRoBGmdWzyvdXHE0hv7AwD+ufUCqus5A4iIqDkGFaIuJAgCls8eiGdmxF71nLtHhyHc2wXlNQ3YkJLTjdUREdk/BhUimamUCmmsyqcHMiGKoswVERHZDwYVIjtw24gQqFUKnM3TITmrvMXzJVX1ePbL4/jNBweRnFnW/QUSEcmEmxIS2QGtiyNujg/C18ey8emByxge5ik9t/lkHv684RRKqvUAgF8uFmPqAD+U1+hxuaQGT0yNxn3jI+QqnYioS7FFhchO/CbR1P2z8UQeCnR1AIAP96Tj0c+OoaRaj1h/d8wfFgwA2HGuEMcyy1FSrcerW86juKpetrqJiLoSW1SI7ERCiAZxwRqczKnAnLd+wey4AHx6wDRl+XfjI7BsdizUKiXuGxeO3ReKEObtgv/8ko6TORVYsysNf7l5UId+zt82nsHPZwrw+UNjEWyeiZRWVAVfdzU8mu3+TERkD9iiQmQnBEHAG3cmYECAO0qq9VJIeWxKFP5y80CoVUoAQEKoFk9Mi8G8ocF4bqZpNtEnBy4jr6IWWaU1yCiuvurPSC2sxAd705FZWoO1e9MBAAculeDGVUl48vPkLr5CIqJrx6BCZEei/dzx3ePjsfiGKLg7qbBkajSemxkLQRBaPX9ijA9GR3hB32jEjDd2Y+KrOzHl9V145ovjKNTV4dvkbNy/9jC+TTbtJ/R/O9NgmVT05dFs1DUY8M6OizCKwN7UEtQ3GrrrUomIOkQQe/BcSJ1OB41Gg4qKCnh4eLT/AqIeRBTFqwaU5g5nlOL29/YDAFQKAQZRxJX/qgUBeG5mLP758wUYjCI0zg6oqG3AfePCsXZfhnTet4+NwzDzQF5RFLHxRB7WH87Ckmkxra6sS0TUGdfy+c0xKkR2qiMhBQBGhXth7W9HoUZvwIQYH1wsqMIfvj6Bi4VVCNQ4ob+/O5IuFOHVn84DACb398WocE+8/vMFq5ACAMmZ5RgW5onc8los+/oEfrlo2izR3UnFoEJEspC162f37t2YO3cugoKCIAgCNmzYIGc5RD3WlFg/zIkLhIeTA0b088SmJRPxw+MT8Mvvb8BH943CLQlB0rmPT43GHaNCoVI0BaF5Q03PHzOv0bL0ixQppADA2TxdN10JEZE1WYNKdXU1EhISsHr1ajnLIOp1HFUKxIVooFIqoFAIeP32BNw3LhxLpsVgVLgX/NydMHNwAADgxkH+uGNkKABTi0p2WQ0OXCqFIADrHhoLALhcWnPVfYhEUcSOcwWoqGnonosjoj5F1q6f2bNnY/bs2R0+v76+HvX1TetF6HT8Xx5RRziqFHjxlsFWx56fOwghns747fgIuDmpIAhATnktPthjmg00NsIbYyO94e+hRoGuHufyKzGin2eL9/7sYCb+vOEUbh8RgtduT+iW6yGivqNHzfpZsWIFNBqN9BUaGip3SUQ9lr+HE5bPGYgAjRPc1CrE+rsDAD7ZfxlAU3fQwEDTQLczV+n++fqYaUbRgfSSri6ZiPqgHhVUli9fjoqKCukrKytL7pKIeo1hYVoAQKNRhINSwOwhgQCagkpr41SySmuQnFlu/r4WpeZl/omIbKVHBRW1Wg0PDw+rLyKyjWGhTd06U2L9oHExrVI7qI2gsulkntXjE9nlXVcgEfVJPSqoEFHXGd5PK31v6fYBmlpUzuVVwmC0XqDlh+O5AAAXR9OquSezK676/unF1e0uKLfnYrG0zxEREcCgQkRmkT5uGBzkgUgfV0wb4C8dj/BxhZODArUNBlwuaVqeP62oCqdzdVAqBPzOvHvzcXNQKaysw7n8phaYn07l44bXd+GBj4/gamtMHkovxa8/ONjmOUTU98g666eqqgqpqanS4/T0dKSkpMDLywthYWEyVkbU9ygUAjY+MQEGowiVsun/MEqFgFh/dxzPrsBZc6vKz2cKsONcIQBgQrQPJsf64t2dqTiZU45GgxF3vn8AGSXV+Oi+URgf7YMVm88CAH65WIx1h7OwcHTLf98HL5kG457MqcDpXB2GBGu64aqJyN7JGlSOHDmCG264QXq8dOlSAMC9996LtWvXylQVUd8lCAJUypYr4g4M9MDx7Ar865dLOJurg95glJ5bMCIEg4M8oBCAAl09PtqbgXTzxoi//+oEfj22Hy6X1ECpEGAwivj7prOYEuuLQI2z1c84kdPUbfT1sWwGFSICIHPXz5QpUyCKYosvhhQi+zIoyDRO5XhWOfQGI8ZFeWP57AH44uFEzI0PhIujCjF+punNr/9sWqpfpRBQWFmPVVsvAACev3kQhoZqUVXfiD98fbLFeJfm41u+S8mFvtEIIiKOUSGidsU1a91YemN/fHr/GDw8OQqjI7ykPYniQ0zn1Dca4eygxIf3jZKW6Y/wccXdY8Lw2m3xcFQqkHShCH/ecFIai1Koq0O+rg6CAPi4OaK0Wo+d5wu7+SqJyB4xqBBRu4aGavH3+UPwvwfGYMm0GCgULbuHLEEFAO4cFYpJ/X3xxzkD4aZW4cVbBsNBqUCMvzvevGsoFALw+aEs/MO8UeJJc7dPtK8bFgwPAQB8fTS7G66MiOwdgwoRtUsQBCwa0w/jon2uek5CqBYAoBCA+yeYZgH9bkIETr00E5P7+0rnzYkLxCvz4wAA7yWlYc/FYimoxIVosGCEKajsOFcIXR33DyLq6xhUiMgm4oI1eHp6f/xjQTxCvVzaPPeu0WH49VjTzJ9//3JJGp8SH6xBf393hHm5oNEoSqvetkUUxatumPj10Wys+PEsjEZOdybqqRhUiMgmBEHAk9NjcPvIju3B9eDESAgCkHShCPvNU5PjQrQAgJHmzQ+PZJS2+z6vbjmP+Jd+xkd7062Ol9fosfybk3h/9yXuQ0TUgzGoEJEs+nm74saBpoXlavQGKISm5fpHhnsBAI5klLX5HqIo4ptj2TAYRbz0wxms3tm0LtP3x3OladQdaZkhIvvEoEJEsrGMZQGA/v7ucDYvxT8q3NSikpxVhgbD1acpny+oRIGuHuaJR3hty3n8a3caAODLI02DcY9dbjvwEJH9YlAhItmMjvDCYPMaLc2nQEf5ukHr4oC6BiNO57bcDNEi6XwRAOCGWD/8flYsAODVn87jyyNZ0gBdAEjOKocoiiiv0eOZL45j65mCrrgcIuoCDCpEJBtBEPDiLYMxNFSLX4/tJx1XKASMCGt/nErSBVNQmRTjg0cnR2FOXAAajSKe++oEAGDqAD84KhUordbjckkNPtqbga+PZePhT47gyyNZna67vEaPO9/fj1Xmxe2IqOswqBCRrEaFe2HD4vHS9GaL5uNUfjiei3ErtuPp9Sk4ZW4pqa5vlMawTI71gyAI+PutcfD3UEvvcffoMAwJNrXYHL1chm+TcwAARhF47qsT+PxQZqdq/uxgJg6ml+LtHak4ym4loi7FoEJEdskyTiXpQhGeXJeM3Io6fJucg5vf2YNHPz2K7ecKoTcYEeblgnBv03RoT1dHvH57AgQBCNI4YXKsL4abW2Y+3JuOzNIauDoqpanRL3x/+qpTm6/GYBTxv4NNAeflH05z+jNRF2JQISK7FBeigaNKgdoGA4wicEtCEG4dGgSVQsDmU/lYuj4FADCpv4+0jD8ATIzxxQ+PT8AXjyTCQanAcPNUZ8tYl1lDAvHXeUMQrHWGvtGIQx2YAt3crvOFyCmvhcbZAW5qFY5nV+Abc0sNEdkegwoR2SW1Sim1qvxqWDDeuHMo3rxrGNY/nAhvV0c0mlsxJvf3a/HaIcEahHiaWlksLSoWC4YHQxAETDCvsrsvtfia6vr0wGUAwB0jQ/DE1GgAwD9+Ooe6BkOH3yPpQhEe+Pgw9zMi6gAGFSKyW6/dloA1i4bjtdsToDTvLzSinyc2LB6PIcEeiPBxxfho7zbfI0DjhECNEwAgUOOEsZGm88fHmILKntSmxeAKdXXSRolXEkURx7PKscs8gHfRmH64b3w4/D3UKKqsx740U+A5nlWOxBXbWx2sW1HTgCWfJ+PeDw9h29lCvLLp7LX8cRD1SSq5CyAiupogrTOCtM4tjod6ueCHxydAFNHqBolXGh3hhe9ScnHrsGDp/HFRpsByNk+H4qp6rD+chde2nMewMC2emxGLukYDNp/MR3ZZLYyiiLyKOmSW1gAAJsb4INzHFQAwY1AAPjlwGVvPFGLqAH/8a/cl5FXU4d+/XGqxSu/Kn87h++O5sJR8sbAKWaU17W45QNSXsUWFiHokQRA6FFIA4A+zB+BPcwZiydQY6ZiPmxoDzSvhbkjOwTs7LgIwrWJ7938O4ndrj+DLo9nYf6kEB9NLkVlaAwelgIkxPvj7rXHS+9w4yLS67vazBdDVNWDbWdMaLRcKTCGkud3m1ph3Fg7HKPOsph3n2P1zvY5klOLGVUk4fI3jjahnYIsKEfV6gRpnPDgpssXx8VHeOJunwz9+OocGg4iEUC3igzX4/FAmvFwdMScuEMPCtFAqBLipVRgZ7gU3tfWvzTGRpmOFlfX455bzqG9sWkl3+9kC3DfetPpubnktcsproVQImBLri5zyGhxML8X2c4W4d1x4l15/ZxRW1uH7lFzcOSoU7k4OAEzjc9QqRYf3c+ou6w9n4WJhFT49cFkKgNR7MKgQUZ81PsYH/9mTjgaDaVzKn+YMxOgIL7wwdxAUHWyxUauUmNzfF5tO5uHj/aaBtoEaJ+RV1GH7uUIpqFj+tz84yAOuahWmDvDHKz+ew4G0ElTXN8JV3X2/jr9LycFnBzKxYkEconzdWjyvbzTi/rVHcDKnAufyK/H67Qk4cKkEf95wCoIA3DDADz5u6lbeWR7pxdUAgBPZFe2cST0Ru36IqM8aHe4FB6UpjEwf6IfREab/jauUig53KwHA9EHWM49emW/qGjpwqQSVdQ0AgEPppqBi+R9/lK8r+nm7QG8wYk8rM4/qGgz428Yz2HPx2mYlNVdR29BicPCW0/l4en0KDmWU4u9XGcz7xrYL0hYE3xzLRmphFVZtvQAAEMWO7WrdnS6Zg0p6cTUqahtkroZsjUGFiPosV7UKN8UFQuPsgGWzBnT6fW6I9ZNmJSWEanHDAD9E+LiiwSDiF3PQsLSoWIKKIAiYOsAUcHacbTlOZd2hTPxnTzru//gwzrSx39HVfH4oE0Nf/hn/tytNOnbgUgme+DwZlvXpdpwrxLFM65V1D1wqwXtJptdE+LjCKAKPfXZUCloAcND8fX5FHV78/jSyy6zH4nSn8ho9Sqv10uPTOWxV6W0YVIioT3vjzqE4/KfpiPF37/R7aF0cMTbSFEDmDw0CAEwzh5BtZwtQXqPHhYIqAE0r7gKQgsqPJ/Ow84pBtZbl/usbjXj0s6NWLQXlNXq8l5SGAl1dq/Wcz6/EC9+fhigCG0/kATBNr166PgX6RiNmDPLHr4YHm67f3FICABnF1Xj8f8kQRdM6MWt+PRyCAKn2fuYVgC2h5dWfzmHtvoyrtsx0h7SiaqvHJxhUeh0GFSLq0wRBgKPq+n8VrvxVPF6ZHydtrjhtoGk20KYTefjPL+kAgEhfV3g3G9sxNtIbCaFaVNY34rdrD+OlH07DYBSRVlSF49kVUCoEBGmccLmkBs9+eVx63VvbL2Ll5nP49X8OorKuAbV6A5auT8HCfx3A54cyseTzZOjNg3rP5etQUdOACwVVyK2og7ODEm/dNQxPT+8PlULALxeLsfFELjJLavDrDw6iuKoeAwLc8fzcwRgQ4IF5CabgpVYp8O7C4QCAM3k6FOrqsOV0PgBg+9lCVNTI0+VyqajK6vGJ7HJZ6qCuw8G0REQ2EOrlgrvHhEmPx0R44YZYX+w8X4R3d6YCMI2Jac5BqcD6h8Zi5WZTy8RHezPg5eIIvcEUMibF+OCZGbGY/397sfVMAc7l6xDr744tp0wB4WJhFZZ8ngxdXaO0OeL+S6YF7HzcHOGoVCC3og5HLpcio8TUPTM6wgvOjkqEerng9pGh+PxQJh7/X7JUU7i3Cz65f4w0u+m5WQOQVVaLWxKCEBeiQbi3CzJKarBy8zlU602r8eoNRmw8mYtFY5p2wLYVo1HExcIqhPu4QK1StnjeMpA20tcVl4qqOaC2F2KLChFRF1AoBLx793Bp92YArU6ddXJQ4sVbBuMfC0wDcN/cfhGfmTc9nD88BEOCNbgh1tRFtCE5FydzKpBbUQcnBwUcVQrsPF+Eo5fL4OGkwuM3RCPK1xVqlQKr7hiKSf19AZi6avaaB+xatg4AgN/PjMW8oUHwdnUEYJqt9Mn9Y+Dr3tTqE6x1xtePjpOmUFsGHFv2NwrwMK36+82x9vc7Kq3Wo7iq/qqr/7bm+e9PYeabu5Hw0s+458NDLQbyXjJ3/cxLMHVlZZfVSmNWLKsJ7zxfeE0/k+wLW1SIiLqIq1qFD+8bhdvW7EdxVT0mxvhc9dw7RoZiX1oJvkvJRWm1Hm5qFW40dx/NHxaMn88U4PuUHFj2X5w6wA8zBgXgqfUp8PdQ47+/G4PYAHc8M6M/DEYRKqUCxVX1WHc4C3vTipFu/kAf12zLAU9XR7x11zCIoojcijp4OKmkNVOuZnSEN744ki09XnVHAn79wUEcvVyGjOJqacXeD/akY9OJXPx9fhwGBnrgeFY57vzXftQ1GKFxdsD4aG/8Y0F8mz9vf1oJPj1gCm11DUbsvlCEQl0dfnpqknTOpWJT1098qEZqVUnJKsOpHB3WHcpEboVpHM9/7hmJ6ebF+ahnYYsKEVEX8nN3wpanJiHpuRvgZ259aI0gCPjbrUMQ6mXaMmDm4AA4O5q6Om4Y4Ad3JxVyK+rw8b4M6flbhwVj+zOTsW3pZMQGuEvvo1KafrVbWj9O5ehQrTfAy9URAwM8cCVBEBCsdW43pADW3VeDgzwwLtoHE2NMLTfrzfsbfXU0G3/deAbHMsvxwMdHTIN0Pz+GugZTl1ZFbQN+PJmPx/+XjEaDseUPgWl69h+/PQkAWDg6DD88PgEKATiXXynNMjIYRalLK8rHDfHBGgDAU+tSsGrrBSmkAMAvF4vavba2lFXr8cXhLGnsD3UfBhUioi7m7Ki06k65GncnB3x47yjcPSYMz8zoLx13clBi9pAAAECN3gAHpYAbzDOGonzdrhowQjxdENxsr6RxUd7XtD5Ma0K9nKXunluHmrpbLDOI1uxKw28+OIjl35wAALg4KpFTXouZb+5GVmktQr2ccehP0/Df342Gk4MCSReKzLOTWnbLvL39ItKLq+HvocbyOQMQF6LBiH6mGVOWbQdyy2uhbzTCUaVAsKcz4kK0AABdXSOcHZR49bZ4rLojAQBwKKOsxc+4Fis3n8Pvvz6B95PS2j+ZbIpBhYjIjsT4u+OV+XEtNmO8dViw9H1ilA88OtD6ATS1qgDW41M6SxAE/GH2ANwUF4g7R5uW0r85Pgi/HR8OpXkWUYNBxE1xgdiweDzc1CrUNxrhoBTw7sLh8HN3wqT+vnjrrmEQBOCzg5n4r3lFX4vMkhr8+5dLAICX5w2RrtUyk2qbed2ZNPOMn3BvFygVAiZE+0AQgBBPZ3zz2DjcMTJUuuZz+Tro6jo3M0kURSSZ92n60TyQmboPgwoRUQ8wNsJbasmYObjjYy2aB5XxNggqgCk0rV40XAoQSoWAF+YOxpanJuGWhCDMGxqEf96RgP7+7li9aDhi/Nzwyvw4JIRqpfeYOTgAy2ebFtn768YzOHq5aZDsP7aY9l6aGOODmYMDpOPTB5pakQ6klaCqvlEaSBthHhcTG+CO3c/dgG1LJ0sbTvp5OKGftwtEETh2uXOtKunF1cg3r1lzNk/XYrNJe7PjXAGm/nMX9rWy4nFPxKBCRNQDKBQC/nlHAh6cGIHbRoR0+HUTY3zg5KBAfIgGoV4uXVghEO3nhrcXDsNbdw2Dk4NpfM3k/r7YunRyqxsZPjgxEjfFB6LRKOKxz44hp7wWxzLLsOlEHgQB+OOcgVbnR/m6NW07cLFIGkgb2Wy/olAvF+lnW4zsZwprhzNKIYoitp8twNm8lqv9FlbW4Y/fnsR28w7YFvvSSqwebz1j/Xxb/rbxDG5/bx+Wf3MCH+5Jxy8Xi1Cgq+vwLKRGgxFGY8dnLFXWNeD3X53EpaJq/OW7UzBc8dpvjmXj/rWHkVNe2+H3lBtn/RAR9RDjo32uuVUkxNMF25+ZAjdH+/t1LwgC/rEgHufzK5FaWIUJ/9gBd/P6LbcND5FaRZqfP22APz7cm45/7b6EPPNg2Uhzi8rVjI7wxNfHsnE4owzfH8/Fk+tS4KAU8PrtCZg3tKlL7U/fnsLWMwX438FMPDYlCs/MiIVSIWC/OahYNpvceqYAv5sQ0e71ZZXW4D97TIv9Hb5ijIyHkwox/u64J7GfVQ3NZZfVYP7/7UOYlws+e2BMiwDWmre2XURxVT0A06q936Xk4FfDTcG2vtGAlzeeQXlNA3I/PoKvHkns1s0wO4stKkREvVyw1hkal46NaelubmoV/vWbERgaqoUomgbCOjko8MyM2FbPt3T/HMssR15FHVwcla2uT9PcSPPzKVnl+OtG03L/DQYRT65LwXtJaRBFETvPF2LrmQJp+vf/7UrDo58ehcEoSovoWfaDOpRRirJm+wuVVetxspWF5ixr18T4ueGJqdGYOdgfkT6uUAiQFul7an1Kq100RqOIZ744jqLKehy9XIZXfjTVLYoi6hoMrV5namEl1ppnhU2JNc3EenPbRTSYZ1ZtPVOAcvMKwmfzdFj6Rco1tdbIxf6jFBER9WqRvm7YsHg88ipq8cvFYkT7uSFA0/pU7lERXhgT4YWiynrcNjIEd4wMhY9b2zOqIn1c4e3qiBLzgnORvq6Y3N8XH+3NwMrN57AvrQSZJabxLvePj0B8qBbPfXkcP58pwB++PoHSaj1cHJW4KT4Q7yWl4Vx+JXacK8SCESH45WIRnlyXgtJqPW6KC8Rfbx0CL/MCenvNLTGz4wKx9MamWVz1jQZcKqrGe0lp+C4lF0vWpeDHJROspq9/sCcdB9NLoVYpUN9oxH/3X4bG2QG7LxbjVE4FXl0QjwXNugALdXV4an0KGo0ipg/0w9sLh2HSqzuRWVqDL49k4+4xYVh/2DR9fPpAP+y+UIwtpwuwausFPDuz9VBoLwSxBy/Xp9PpoNFoUFFRAQ+PlmsDEBERAcDDnxzBltOmsSX/e2AMxkX74L/7M/C3TWeltVF83dXY8cxkuDs54NMDl/HnDaek10+J9cXa347Gqp/P4+0dqXBUKjAk2APJWeVo/inq4+aIj+4bjSHBHhj1920ortJj3UNjMTbSG1eq1Rsw///24lx+JUb288Q7dw9DgIcTtpwuMO3XZDBixa/ikFFSjfeTLlm91tlBiY1LJiDK1w2ncirw4H+PIK+iDhpnB/zw+ASEebvggz3p+OvGM3BTq/DmnUPx4CdHIIrA7uduwOGMUjxj3j/qrbuGXrX7qatcy+c3u36IiKjXmzbANFNqwfAQjDOP87knMRw/LpmAhBANFALw4tzB0po0i8aESbtbA6Y1aADg9pGhiPRxhd5gxLFMU0i5a1QovnokEbH+7iiu0uPFH07jQkEViqv0cHJQYFiYttWanB2VWL1oOFwdlThyuQw3vL4Lt7+3H498ehR6gxHTB/rhrlGheHZGLCZE+8BdrcIjk6OQGOmN2gYDlnyejJd+OI35/7cXeRV1iPR1xYbF4xFm3uX6N2P7YUyEF6rqG/HAf00hJTHSG2HeLlgwIgQPT44EADz31Qn8e/clrNmVhh+O59pddxBbVIiIqNczGkWcyq3A4CANlFcseieKIsprGuBp7rKxKKqsx6w3d6O0Ro+fnpwkrf4riiLSi6ux/1IJQj1dpD2VCnV1mPDqTugbjZg52B9bThdgYowPPrl/TJu1ncqpwEs/nJYG3DooBTw4MRJPTI2RVie2fFQLgoD8ijrMfms3yprtWD1jkD9euz0BGmfrsUgVNQ247b19uFhomiH15p1DpTV5DEYRD39yRFqXxmJCtA9euz0egRrrtXxs6Vo+vxlUiIiIriKnvBb5FbUY0a/tAbsWz393ymoBu2WzBuDRKVHtvk4URWw5nY/9aSX4TWI4ov3c2jx/+9kCPPrpMUT5ueFPcwZiQhv7SOWU1+KO9/ZDoQC2Pj3ZavZQVX0jXvz+NCpqG+DiqMSW0/moazBCrVLAx00NZ0clpg3ww/IrpopfLwYVIiIiGeSU12LyqzvRaO4++f7x8Yg3L+1va7V6A5wcFBCE9rdFqG80QCEIcFC2PeLjUlEVnv7iOI5nlUvH5g8Lxht3Dr3Oaq1dy+c3Z/0QERHZSLDWGQuGh2D9kSx4OKkwOEjTZT/L0i3UEWpVx86N9HXDt4+Ow6XialTVN6JG3yjNYpILgwoREZENPTEtGsezy3FTXGCL8TA9gUIhtNv11J0YVIiIiGwoxNMFPz01Se4yeg1OTyYiIiK7xaBCREREdotBhYiIiOwWgwoRERHZLQYVIiIislsMKkRERGS3GFSIiIjIbjGoEBERkd1iUCEiIiK7xaBCREREdotBhYiIiOwWgwoRERHZLQYVIiIislsMKkRERGS3VHIXcD1EUQQA6HQ6mSshIiKijrJ8bls+x9vSo4NKZWUlACA0NFTmSoiIiOhaVVZWQqPRtHmOIHYkztgpo9GI3NxcuLu7QxAEm763TqdDaGgosrKy4OHhYdP3tge9/foAXmNv0NuvD+A19ga9/foA21+jKIqorKxEUFAQFIq2R6H06BYVhUKBkJCQLv0ZHh4evfYvHtD7rw/gNfYGvf36AF5jb9Dbrw+w7TW215JiwcG0REREZLcYVIiIiMhuMahchVqtxgsvvAC1Wi13KV2it18fwGvsDXr79QG8xt6gt18fIO819ujBtERERNS7sUWFiIiI7BaDChEREdktBhUiIiKyWwwqREREZLcYVFqxevVqhIeHw8nJCWPGjMGhQ4fkLqnTVqxYgVGjRsHd3R1+fn649dZbcf78eatzpkyZAkEQrL4eeeQRmSq+Ni+++GKL2gcMGCA9X1dXh8WLF8Pb2xtubm5YsGABCgoKZKz42oWHh7e4RkEQsHjxYgA98/7t3r0bc+fORVBQEARBwIYNG6yeF0URzz//PAIDA+Hs7Izp06fj4sWLVueUlpZi0aJF8PDwgFarxf3334+qqqpuvIqra+v6GhoasGzZMsTFxcHV1RVBQUG45557kJuba/Uerd33lStXdvOVXF179/C+++5rUf+sWbOszrHnewi0f42t/bsUBAGvvfaadI4938eOfD505HdoZmYmbrrpJri4uMDPzw/PPfccGhsbbVYng8oV1q9fj6VLl+KFF17AsWPHkJCQgJkzZ6KwsFDu0jolKSkJixcvxoEDB7B161Y0NDRgxowZqK6utjrvwQcfRF5envT16quvylTxtRs8eLBV7Xv27JGee/rpp/HDDz/gyy+/RFJSEnJzc/GrX/1Kxmqv3eHDh62ub+vWrQCA22+/XTqnp92/6upqJCQkYPXq1a0+/+qrr+Ltt9/Ge++9h4MHD8LV1RUzZ85EXV2ddM6iRYtw+vRpbN26FRs3bsTu3bvx0EMPddcltKmt66upqcGxY8fwl7/8BceOHcM333yD8+fP45Zbbmlx7ssvv2x1X5944onuKL9D2ruHADBr1iyr+j///HOr5+35HgLtX2Pza8vLy8OHH34IQRCwYMECq/Ps9T525POhvd+hBoMBN910E/R6Pfbt24ePP/4Ya9euxfPPP2+7QkWyMnr0aHHx4sXSY4PBIAYFBYkrVqyQsSrbKSwsFAGISUlJ0rHJkyeLTz75pHxFXYcXXnhBTEhIaPW58vJy0cHBQfzyyy+lY2fPnhUBiPv37++mCm3vySefFKOiokSj0SiKYs++f6IoigDEb7/9VnpsNBrFgIAA8bXXXpOOlZeXi2q1Wvz8889FURTFM2fOiADEw4cPS+ds3rxZFARBzMnJ6bbaO+LK62vNoUOHRADi5cuXpWP9+vUT33jjja4tzkZau8Z7771XnDdv3lVf05PuoSh27D7OmzdPnDp1qtWxnnQfr/x86Mjv0B9//FFUKBRifn6+dM6aNWtEDw8Psb6+3iZ1sUWlGb1ej6NHj2L69OnSMYVCgenTp2P//v0yVmY7FRUVAAAvLy+r45999hl8fHwwZMgQLF++HDU1NXKU1ykXL15EUFAQIiMjsWjRImRmZgIAjh49ioaGBqv7OWDAAISFhfXY+6nX6/Hpp5/id7/7ndVGnD35/l0pPT0d+fn5VvdNo9FgzJgx0n3bv38/tFotRo4cKZ0zffp0KBQKHDx4sNtrvl4VFRUQBAFardbq+MqVK+Ht7Y1hw4bhtddes2lzenfYtWsX/Pz8EBsbi0cffRQlJSXSc73tHhYUFGDTpk24//77WzzXU+7jlZ8PHfkdun//fsTFxcHf3186Z+bMmdDpdDh9+rRN6urRmxLaWnFxMQwGg9UfOAD4+/vj3LlzMlVlO0ajEU899RTGjx+PIUOGSMfvvvtu9OvXD0FBQThx4gSWLVuG8+fP45tvvpGx2o4ZM2YM1q5di9jYWOTl5eGll17CxIkTcerUKeTn58PR0bHFL39/f3/k5+fLU/B12rBhA8rLy3HfffdJx3ry/WuN5d609u/Q8lx+fj78/PysnlepVPDy8upx97aurg7Lli3DwoULrTZ7W7JkCYYPHw4vLy/s27cPy5cvR15eHlatWiVjtR03a9Ys/OpXv0JERATS0tLwxz/+EbNnz8b+/fuhVCp71T0EgI8//hju7u4tupZ7yn1s7fOhI79D8/PzW/23annOFhhU+pDFixfj1KlTVmM4AFj1CcfFxSEwMBDTpk1DWloaoqKiurvMazJ79mzp+/j4eIwZMwb9+vXDF198AWdnZxkr6xoffPABZs+ejaCgIOlYT75/fV1DQwPuuOMOiKKINWvWWD23dOlS6fv4+Hg4Ojri4YcfxooVK3rEUu133XWX9H1cXBzi4+MRFRWFXbt2Ydq0aTJW1jU+/PBDLFq0CE5OTlbHe8p9vNrngz1g108zPj4+UCqVLUY0FxQUICAgQKaqbOPxxx/Hxo0bsXPnToSEhLR57pgxYwAAqamp3VGaTWm1WvTv3x+pqakICAiAXq9HeXm51Tk99X5evnwZ27ZtwwMPPNDmeT35/gGQ7k1b/w4DAgJaDHBvbGxEaWlpj7m3lpBy+fJlbN261ao1pTVjxoxBY2MjMjIyuqdAG4uMjISPj4/097I33EOLX375BefPn2/33yZgn/fxap8PHfkdGhAQ0Oq/VctztsCg0oyjoyNGjBiB7du3S8eMRiO2b9+OxMREGSvrPFEU8fjjj+Pbb7/Fjh07EBER0e5rUlJSAACBgYFdXJ3tVVVVIS0tDYGBgRgxYgQcHBys7uf58+eRmZnZI+/nRx99BD8/P9x0001tnteT7x8AREREICAgwOq+6XQ6HDx4ULpviYmJKC8vx9GjR6VzduzYAaPRKAU1e2YJKRcvXsS2bdvg7e3d7mtSUlKgUChadJf0FNnZ2SgpKZH+Xvb0e9jcBx98gBEjRiAhIaHdc+3pPrb3+dCR36GJiYk4efKkVei0BO9BgwbZrFBqZt26daJarRbXrl0rnjlzRnzooYdErVZrNaK5J3n00UdFjUYj7tq1S8zLy5O+ampqRFEUxdTUVPHll18Wjxw5Iqanp4vfffedGBkZKU6aNEnmyjvmmWeeEXft2iWmp6eLe/fuFadPny76+PiIhYWFoiiK4iOPPCKGhYWJO3bsEI8cOSImJiaKiYmJMld97QwGgxgWFiYuW7bM6nhPvX+VlZVicnKymJycLAIQV61aJSYnJ0uzXlauXClqtVrxu+++E0+cOCHOmzdPjIiIEGtra6X3mDVrljhs2DDx4MGD4p49e8SYmBhx4cKFcl2SlbauT6/Xi7fccosYEhIipqSkWP27tMyS2Ldvn/jGG2+IKSkpYlpamvjpp5+Kvr6+4j333CPzlTVp6xorKyvFZ599Vty/f7+Ynp4ubtu2TRw+fLgYExMj1tXVSe9hz/dQFNv/eyqKolhRUSG6uLiIa9asafF6e7+P7X0+iGL7v0MbGxvFIUOGiDNmzBBTUlLEn376SfT19RWXL19uszoZVFrxzjvviGFhYaKjo6M4evRo8cCBA3KX1GkAWv366KOPRFEUxczMTHHSpEmil5eXqFarxejoaPG5554TKyoq5C28g+68804xMDBQdHR0FIODg8U777xTTE1NlZ6vra0VH3vsMdHT01N0cXER58+fL+bl5clYceds2bJFBCCeP3/e6nhPvX87d+5s9e/lvffeK4qiaYryX/7yF9Hf319Uq9XitGnTWlx7SUmJuHDhQtHNzU308PAQf/vb34qVlZUyXE1LbV1fenr6Vf9d7ty5UxRFUTx69Kg4ZswYUaPRiE5OTuLAgQPFV155xepDXm5tXWNNTY04Y8YM0dfXV3RwcBD79esnPvjggy3+w2fP91AU2/97Koqi+P7774vOzs5ieXl5i9fb+31s7/NBFDv2OzQjI0OcPXu26OzsLPr4+IjPPPOM2NDQYLM6BXOxRERERHaHY1SIiIjIbjGoEBERkd1iUCEiIiK7xaBCREREdotBhYiIiOwWgwoRERHZLQYVIiIislsMKkRERGS3GFSIqEPCw8Px5ptvdvj8Xbt2QRCEFhua9VbX+udDRB2jkrsAIuoaU6ZMwdChQ2324Xn48GG4urp2+Pxx48YhLy8PGo3GJj+fiPomBhWiPkwURRgMBqhU7f8q8PX1vab3dnR0tNk270TUd7Hrh6gXuu+++5CUlIS33noLgiBAEARkZGRI3TGbN2/GiBEjoFarsWfPHqSlpWHevHnw9/eHm5sbRo0ahW3btlm955VdG4Ig4D//+Q/mz58PFxcXxMTE4Pvvv5eev7LrZ+3atdBqtdiyZQsGDhwINzc3zJo1C3l5edJrGhsbsWTJEmi1Wnh7e2PZsmW49957ceutt7Z5vXv27MHEiRPh7OyM0NBQLFmyBNXV1Va1//Wvf8XChQvh6uqK4OBgrF692uo9MjMzMW/ePLi5ucHDwwN33HEHCgoKrM754YcfMGrUKDg5OcHHxwfz58+3er6mpga/+93v4O7ujrCwMPzrX/9qs24iah+DClEv9NZbbyExMREPPvgg8vLykJeXh9DQUOn5P/zhD1i5ciXOnj2L+Ph4VFVVYc6cOdi+fTuSk5Mxa9YszJ07F5mZmW3+nJdeegl33HEHTpw4gTlz5mDRokUoLS296vk1NTV4/fXX8cknn2D37t3IzMzEs88+Kz3/j3/8A5999hk++ugj7N27FzqdDhs2bGizhrS0NMyaNQsLFizAiRMnsH79euzZswePP/641XmvvfYaEhISkJycjD/84Q948sknsXXrVgCA0WjEvHnzUFpaiqSkJGzduhWXLl3CnXfeKb1+06ZNmD9/PubMmYPk5GRs374do0ePtvoZ//znPzFy5EgkJyfjsccew6OPPorz58+3WT8RtcNm+zATkV2ZPHmy+OSTT1ods2xbv2HDhnZfP3jwYPGdd96RHvfr10984403pMcAxD//+c/S46qqKhGAuHnzZqufVVZWJoqiKH700UciADE1NVV6zerVq0V/f3/psb+/v/jaa69JjxsbG8WwsDBx3rx5V63z/vvvFx966CGrY7/88ouoUCjE2tpaqfZZs2ZZnXPnnXeKs2fPFkVRFH/++WdRqVSKmZmZ0vOnT58WAYiHDh0SRVEUExMTxUWLFl21jn79+om//vWvpcdGo1H08/MT16xZc9XXEFH72KJC1AeNHDnS6nFVVRWeffZZDBw4EFqtFm5ubjh79my7LSrx8fHS966urvDw8EBhYeFVz3dxcUFUVJT0ODAwUDq/oqICBQUFVq0USqUSI0aMaLOG48ePY+3atXBzc5O+Zs6cCaPRiPT0dOm8xMREq9clJibi7NmzAICzZ88iNDTUqtVp0KBB0Gq10jkpKSmYNm1am7U0//MQBAEBAQFt/nkQUfs4mJaoD7py9s6zzz6LrVu34vXXX0d0dDScnZ1x2223Qa/Xt/k+Dg4OVo8FQYDRaLym80VRvMbqrVVVVeHhhx/GkiVLWjwXFhZ2Xe/dnLOzc7vnXOufBxG1jy0qRL2Uo6MjDAZDh87du3cv7rvvPsyfPx9xcXEICAhARkZG1xZ4BY1GA39/fxw+fFg6ZjAYcOzYsTZfN3z4cJw5cwbR0dEtvhwdHaXzDhw4YPW6AwcOYODAgQCAgQMHIisrC1lZWdLzZ86cQXl5OQYNGgTA1Fqyffv2675OIro2bFEh6qXCw8Nx8OBBZGRkwM3NDV5eXlc9NyYmBt988w3mzp0LQRDwl7/8RZaWgCeeeAIrVqxAdHQ0BgwYgHfeeQdlZWUQBOGqr1m2bBnGjh2Lxx9/HA888ABcXV1x5swZbN26Fe+++6503t69e/Hqq6/i1ltvxdatW/Hll19i06ZNAIDp06cjLi4OixYtwptvvonGxkY89thjmDx5stRN9sILL2DatGmIiorCXXfdhcbGRvz4449YtmxZ1/6hEPVxbFEh6qWeffZZKJVKDBo0CL6+vm2ON1m1ahU8PT0xbtw4zJ07FzNnzsTw4cO7sVqTZcuWYeHChbjnnnuQmJgojTdxcnK66mvi4+ORlJSECxcuYOLEiRg2bBief/55BAUFWZ33zDPP4MiRIxg2bBj+9re/YdWqVZg5cyYAUxfNd999B09PT0yaNAnTp09HZGQk1q9fL71+ypQp+PLLL/H9999j6NChmDp1Kg4dOtQ1fxBEJBHE6+0gJiLqIkajEQMHDsQdd9yBv/71r51+n/DwcDz11FN46qmnbFccEXULdv0Qkd24fPkyfv75Z0yePBn19fV49913kZ6ejrvvvlvu0ohIJuz6ISK7oVAosHbtWowaNQrjx4/HyZMnsW3bNmnQKxH1Pez6ISIiIrvFFhUiIiKyWwwqREREZLcYVIiIiMhuMagQERGR3WJQISIiIrvFoEJERER2i0GFiIiI7BaDChEREdmt/wfGdERCwddAaAAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 梯度裁剪\n",
    "def grad_clipping(model, theta=1):\n",
    "    params = [p for p in model.parameters() if p.requires_grad]\n",
    "    norm = torch.sqrt(sum(torch.sum((p.grad ** 2)) for p in params))\n",
    "    if norm > theta:\n",
    "        for param in params:\n",
    "            param.grad[:] *= theta / norm\n",
    "    \n",
    "\n",
    "# 训练\n",
    "from torch.utils.data import DataLoader\n",
    "from torch.optim import SGD, Adam\n",
    "import numpy as np\n",
    "from tqdm import tqdm, trange\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def train_rnn_lm(data_loader, rnn, vocab_size, hidden_size=128, \n",
    "                 epochs=200, learning_rate=1e-3):\n",
    "    # 准备模型、优化器等\n",
    "    rnn_lm = RNNLM(rnn, vocab_size, hidden_size)\n",
    "    optimizer = Adam(rnn_lm.parameters(), lr=learning_rate)\n",
    "    rnn_lm.zero_grad()\n",
    "    rnn_lm.train()\n",
    "\n",
    "    epoch_loss = []\n",
    "    with trange(epochs, desc='epoch', ncols=60) as pbar:\n",
    "        for epoch in pbar:\n",
    "            for step, batch in enumerate(data_loader):\n",
    "                loss = rnn_lm(batch)\n",
    "                pbar.set_description(f'epoch-{epoch}, ' + \\\n",
    "                    f'loss={loss.item():.4f}')\n",
    "                loss.backward()\n",
    "                grad_clipping(rnn_lm)\n",
    "                optimizer.step()\n",
    "                rnn_lm.zero_grad()\n",
    "            epoch_loss.append(loss.item())\n",
    "\n",
    "    epoch_loss = np.array(epoch_loss)\n",
    "    # 打印损失曲线\n",
    "    plt.plot(range(len(epoch_loss)), epoch_loss)\n",
    "    plt.xlabel('training epoch')\n",
    "    plt.ylabel('loss')\n",
    "    plt.show()\n",
    "\n",
    "sent_tokens = np.array(sent_tokens)\n",
    "print(sent_tokens.shape)\n",
    "vocab_size = len(dataset.token2id)\n",
    "\n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, dtype=torch.long),\\\n",
    "    batch_size=16, shuffle=True)\n",
    "rnn = RNN(128, 128)\n",
    "train_rnn_lm(data_loader, rnn, vocab_size, hidden_size=128,\\\n",
    "    epochs=200, learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ad30e705",
   "metadata": {},
   "source": [
    "接下来仿照循环神经网络实现长短期记忆，同样的接口使得我们可以重用之前的训练代码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "1995d027",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=0.3358: 100%|█| 200/200 [24:46<00:00,  7.43s\n"
     ]
    },
    {
     "data": {
      "image/png": "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7jjw0GQy8cx3xnvdZw2w+HxpMmjqR0RERPyYgoqIiIj4LQUVERER8VsKKiIiIuK3FFRERETEbymoiIiIiN9SUBERERG/paAiIiIifktBRURERPyWgoqIiIj4LQUVERER8VsKKiIiIuK3FFRERETEbymoiIiIiN8K8HUHToVhGABUVVX5uCciIiJystx/t91/x4+nVweV6upqANLS0nzcExEREems6upqbDbbcduYjJOJM37K4XCQn59PREQEJpOpW1+7qqqKtLQ08vLyiIyM7NbX9gd9/fpA19gX9PXrA11jX9DXrw+6/xoNw6C6uprk5GTM5uNXofTqERWz2Uxqaupp/RqRkZF99h8e9P3rA11jX9DXrw90jX1BX78+6N5rPNFIipuKaUVERMRvKaiIiIiI31JQOQar1covfvELrFarr7tyWvT16wNdY1/Q168PdI19QV+/PvDtNfbqYloRERHp2zSiIiIiIn5LQUVERET8loKKiIiI+C0FFREREfFbCiodeP755+nfvz/BwcFMmTKFtWvX+rpLXbZgwQImT55MREQE8fHxXHnllWRlZXm1mTlzJiaTyevjzjvv9FGPO+eXv/xlu74PGzbM83hDQwPz588nJiaG8PBwrr76aoqKinzY487r379/u2s0mUzMnz8f6J3v3/Lly7n88stJTk7GZDLx/vvvez1uGAY///nPSUpKIiQkhNmzZ5Odne3Vpry8nHnz5hEZGUlUVBS33HILNTU1PXgVx3a862tububhhx9m9OjRhIWFkZyczA033EB+fr7Xa3T0vj/22GM9fCXHdqL38KabbmrX/zlz5ni18ef3EE58jR39XJpMJp544glPG39+H0/m78PJ/A7Nzc3l0ksvJTQ0lPj4eH70ox/R0tLSbf1UUDnKf/7zHx544AF+8YtfsHHjRsaOHctFF11EcXGxr7vWJcuWLWP+/PmsXr2aRYsW0dzczIUXXkhtba1Xu9tuu42CggLPx+OPP+6jHnfeyJEjvfq+cuVKz2P3338/H374IW+//TbLli0jPz+fb37zmz7sbeetW7fO6/oWLVoEwLe//W1Pm972/tXW1jJ27Fief/75Dh9//PHH+dOf/sRf/vIX1qxZQ1hYGBdddBENDQ2eNvPmzWPHjh0sWrSIjz76iOXLl3P77bf31CUc1/Gur66ujo0bN/Kzn/2MjRs3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27fPeO2114y4uDjjhhtu8PGVtTreNVZXVxsPPfSQsWrVKiMnJ8dYvHixMWHCBGPw4MFGQ0OD5zX8+T00jBP/OzUMw6isrDRCQ0ONF154od3z/f19PNHfB8M48e/QlpYWY9SoUcaFF15obN682fjss8+MuLg445FHHum2fiqodODZZ5810tPTjaCgIOOss84yVq9e7esudRnQ4ccrr7xiGIZh5ObmGtOnTzeio6MNq9VqDBo0yPjRj35kVFZW+rbjJ+naa681kpKSjKCgICMlJcW49tprjb1793oer6+vN37wgx8Y/fr1M0JDQ42rrrrKKCgo8GGPu2bhwoUGYGRlZXnd31vfvyVLlnT47/LGG280DMO5RPlnP/uZkZCQYFitVmPWrFntrr2srMy47rrrjPDwcCMyMtL4/ve/b1RXV/vgato73vXl5OQc8+dyyZIlhmEYxoYNG4wpU6YYNpvNCA4ONoYPH2787ne/8/oj72vHu8a6ujrjwgsvNOLi4ozAwEAjIyPDuO2229r9D58/v4eGceJ/p4ZhGC+++KIREhJiVFRUtHu+v7+PJ/r7YBgn9zv0wIEDxsUXX2yEhIQYsbGxxoMPPmg0Nzd3Wz9Nrs6KiIiI+B3VqIiIiIjfUlARERERv6WgIiIiIn5LQUVERET8loKKiIiI+C0FFREREfFbCioiIiLitxRURERExG8pqIjISenfvz9PP/30SbdfunQpJpOp3YFmfVVnvz8icnICfN0BETk9Zs6cybhx47rtj+e6desICws76fbTpk2joKAAm83WLV9fRM5MCioiZzDDMLDb7QQEnPhXQVxcXKdeOygoqNuOeReRM5emfkT6oJtuuolly5bxzDPPYDKZMJlMHDhwwDMd8+mnnzJx4kSsVisrV65k3759zJ07l4SEBMLDw5k8eTKLFy/2es2jpzZMJhN///vfueqqqwgNDWXw4MH873//8zx+9NTPq6++SlRUFAsXLmT48OGEh4czZ84cCgoKPM9paWnhnnvuISoqipiYGB5++GFuvPFGrrzyyuNe78qVKznvvPMICQkhLS2Ne+65h9raWq++//rXv+a6664jLCyMlJQUnn/+ea/XyM3NZe7cuYSHhxMZGck111xDUVGRV5sPP/yQyZMnExwcTGxsLFdddZXX43V1ddx8881ERESQnp7OX//61+P2W0ROTEFFpA965plnmDp1KrfddhsFBQUUFBSQlpbmefz//u//eOyxx9i1axdjxoyhpqaGSy65hC+++IJNmzYxZ84cLr/8cnJzc4/7dR599FGuueYatm7dyiWXXMK8efMoLy8/Zvu6ujr+8Ic/8K9//Yvly5eTm5vLQw895Hn897//Pa+//jqvvPIKX331FVVVVbz//vvH7cO+ffuYM2cOV199NVu3buU///kPK1eu5O677/Zq98QTTzB27Fg2bdrE//3f/3HvvfeyaNEiABwOB3PnzqW8vJxly5axaNEi9u/fz7XXXut5/scff8xVV13FJZdcwqZNm/jiiy8466yzvL7GH//4RyZNmsSmTZv4wQ9+wF133UVWVtZx+y8iJ9Bt5zCLiF+ZMWOGce+993rd5z62/v333z/h80eOHGk8++yzntsZGRnGU0895bkNGD/96U89t2tqagzA+PTTT72+1pEjRwzDMIxXXnnFAIy9e/d6nvP8888bCQkJntsJCQnGE0884bnd0tJipKenG3Pnzj1mP2+55Rbj9ttv97pvxYoVhtlsNurr6z19nzNnjleba6+91rj44osNwzCMzz//3LBYLEZubq7n8R07dhiAsXbtWsMwDGPq1KnGvHnzjtmPjIwM47vf/a7ntsPhMOLj440XXnjhmM8RkRPTiIrIGWjSpElet2tqanjooYcYPnw4UVFRhIeHs2vXrhOOqIwZM8bzeVhYGJGRkRQXFx+zfWhoKAMHDvTcTkpK8rSvrKykqKjIa5TCYrEwceLE4/Zhy5YtvPrqq4SHh3s+LrroIhwOBzk5OZ52U6dO9Xre1KlT2bVrFwC7du0iLS3Na9RpxIgRREVFedps3ryZWbNmHbcvbb8fJpOJxMTE434/ROTEVEwrcgY6evXOQw89xKJFi/jDH/7AoEGDCAkJ4Vvf+hZNTU3HfZ3AwECv2yaTCYfD0an2hmF0svfeampquOOOO7jnnnvaPZaenn5Kr91WSEjICdt09vshIiemERWRPiooKAi73X5Sbb/66ituuukmrrrqKkaPHk1iYiIHDhw4vR08is1mIyEhgXXr1nnus9vtbNy48bjPmzBhAjt37mTQoEHtPoKCgjztVq9e7fW81atXM3z4cACGDx9OXl4eeXl5nsd37txJRUUFI0aMAJyjJV988cUpX6eIdI5GVET6qP79+7NmzRoOHDhAeHg40dHRx2w7ePBg3n33XS6//HJMJhM/+9nPfDIS8MMf/pAFCxYwaNAghg0bxrPPPsuRI0cwmUzHfM7DDz/M2Wefzd13382tt95KWFgYO3fuZNGiRTz33HOedl999RWPP/44V155JYsWLeLtt9/m448/BmD27NmMHj2aefPm8fTTT9PS0sIPfvADZsyY4Zkm+8UvfsGsWbMYOHAg3/nOd2hpaeGTTz7h4YcfPr3fFJEznEZURPqohx56CIvFwogRI4iLiztuvcmTTz5Jv379mDZtGpdffjkXXXQREyZM6MHeOj388MNcd9113HDDDUydOtVTbxIcHHzM54wZM4Zly5axZ88ezjvvPMaPH8/Pf/5zkpOTvdo9+OCDrF+/nvHjx/Ob3/yGJ598kosuughwTtF88MEH9OvXj+nTpzN79mwyMzP5z3/+43n+zJkzefvtt/nf//7HuHHjOP/881m7du3p+UaIiIfJONUJYhGR08ThcDB8+HCuueYafv3rX3f5dfr37899993Hfffd132dE5EeoakfEfEbBw8e5PPPP2fGjBk0Njby3HPPkZOTw/XXX+/rromIj2jqR0T8htls5tVXX2Xy5Mmcc845bNu2jcWLF3uKXkXkzKOpHxEREfFbGlERERERv6WgIiIiIn5LQUVERET8loKKiIiI+C0FFREREfFbCioiIiLitxRURERExG8pqIiIiIjf+v8BMCH8+IctzQAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 长短期记忆\n",
    "def gate_params(input_size, hidden_size):\n",
    "    return (nn.Parameter(normal((input_size, hidden_size))),\n",
    "           nn.Parameter(normal((hidden_size, hidden_size))),\n",
    "           nn.Parameter(torch.zeros(hidden_size)))\n",
    "\n",
    "class LSTM(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size):\n",
    "        super(LSTM, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        # 输入门参数\n",
    "        self.W_xi, self.W_hi, self.b_i = gate_params(input_size, hidden_size)\n",
    "        # 遗忘门参数\n",
    "        self.W_xf, self.W_hf, self.b_f = gate_params(input_size, hidden_size)\n",
    "        # 输出门参数\n",
    "        self.W_xo, self.W_ho, self.b_o = gate_params(input_size, hidden_size)\n",
    "        # 候选记忆单元参数\n",
    "        self.W_xc, self.W_hc, self.b_c = gate_params(input_size, hidden_size)\n",
    "        \n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((batch_size, hidden_size), dtype=torch.float),\n",
    "               torch.zeros((batch_size, hidden_size), dtype=torch.float))\n",
    "    \n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        hidden_state, cell_state = states\n",
    "        hiddens = []\n",
    "        for step in range(seq_len):\n",
    "            I = torch.sigmoid(torch.mm(inputs[step], self.W_xi) \\\n",
    "                + torch.mm(hidden_state, self.W_hi) + self.b_i)\n",
    "            F = torch.sigmoid(torch.mm(inputs[step], self.W_xf) \\\n",
    "                + torch.mm(hidden_state, self.W_hf) + self.b_f)\n",
    "            O = torch.sigmoid(torch.mm(inputs[step], self.W_xo) \\\n",
    "                + torch.mm(hidden_state, self.W_ho) + self.b_o)\n",
    "            C_tilda = torch.tanh(torch.mm(inputs[step], self.W_xc) \\\n",
    "                + torch.mm(hidden_state, self.W_hc) + self.b_c)\n",
    "            cell_state = F * cell_state + I * C_tilda\n",
    "            hidden_state = O * torch.tanh(cell_state)\n",
    "            hiddens.append(hidden_state)\n",
    "        return torch.stack(hiddens, dim=0), (hidden_state, cell_state)\n",
    "    \n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, dtype=torch.long), \n",
    "    batch_size=16, shuffle=True)\n",
    "\n",
    "lstm = LSTM(128, 128)\n",
    "train_rnn_lm(data_loader, lstm, vocab_size, hidden_size=128, epochs=200, \n",
    "    learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e6dafe1d",
   "metadata": {},
   "source": [
    "下面仿照长短期记忆实现门控循环单元。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "7c4f3992",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=0.2161: 100%|█| 200/200 [14:41<00:00,  4.41s\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 门控循环单元\n",
    "class GRU(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size):\n",
    "        super(GRU, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        # 更新门参数\n",
    "        self.W_xu, self.W_hu, self.b_u = gate_params(input_size, hidden_size)\n",
    "        # 重置门参数\n",
    "        self.W_xr, self.W_hr, self.b_r = gate_params(input_size, hidden_size)\n",
    "        # 候选隐状态参数\n",
    "        self.W_xh, self.W_hh, self.b_h = gate_params(input_size, hidden_size)\n",
    "        \n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((batch_size, hidden_size), dtype=torch.float),)\n",
    "    \n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        hidden_state, = states\n",
    "        hiddens = []\n",
    "        for step in range(seq_len):\n",
    "            U = torch.sigmoid(torch.mm(inputs[step], self.W_xu)\\\n",
    "                + torch.mm(hidden_state, self.W_hu) + self.b_u)\n",
    "            R = torch.sigmoid(torch.mm(inputs[step], self.W_xr)\\\n",
    "                + torch.mm(hidden_state, self.W_hr) + self.b_r)\n",
    "            H_tilda = torch.tanh(torch.mm(inputs[step], self.W_xh)\\\n",
    "                + torch.mm(R * hidden_state, self.W_hh) + self.b_h)\n",
    "            hidden_state = (1 - U) * hidden_state + U * H_tilda\n",
    "            hiddens.append(hidden_state)\n",
    "        return torch.stack(hiddens, dim=0), (hidden_state,)\n",
    "    \n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, dtype=torch.long), \n",
    "    batch_size=16, shuffle=True)\n",
    "\n",
    "gru = GRU(128, 128)\n",
    "train_rnn_lm(data_loader, gru, vocab_size, hidden_size=128, epochs=200, \n",
    "    learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69537480",
   "metadata": {},
   "source": [
    "下面在循环神经网络的基础上实现多层循环神经网络。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "6eb2e0ed",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=0.3230: 100%|█| 200/200 [08:41<00:00,  2.61s\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAioAAAGwCAYAAACHJU4LAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAABaU0lEQVR4nO3dd3iV9f3/8ec5J3vvRULYe8iWKQIyXDiqFunXrVXBUUetbV21v2K1Ra1SbK2KrVatCwcOhuy99yYhAbL3Hufcvz9OcsiBAAGSnJPk9biuXObc931O3ncOSV5+pskwDAMRERERN2R2dQEiIiIiZ6KgIiIiIm5LQUVERETcloKKiIiIuC0FFREREXFbCioiIiLithRURERExG15uLqAi2Gz2Thx4gSBgYGYTCZXlyMiIiINYBgGRUVFxMXFYTafvc2kRQeVEydOkJCQ4OoyRERE5AKkpqYSHx9/1mtadFAJDAwE7DcaFBTk4mpERESkIQoLC0lISHD8HT+bFh1Uart7goKCFFRERERamIYM29BgWhEREXFbCioiIiLithRURERExG0pqIiIiIjbUlARERERt6WgIiIiIm5LQUVERETcloKKiIiIuC0FFREREXFbCioiIiLithRURERExG0pqIiIiIjbUlBpIMMwKKu0uroMERGRNkVBpYGe+HQHA19cRGpuqatLERERaTMUVBpo6f5MyqqsbDqa6+pSRERE2gwFlQbIL60kt6QSgKM5alERERFpLgoqDXAku8TxuYKKiIhI81FQaYAjWXWDSslZrhQREZHGpKDSAEeyih2fp2gwrYiISLNRUGmAui0q2cWVFFdUu7AaERGRtkNBpQGOZBc7PVb3j4iISPNQUDkHq80guWYAbUSANwApGlArIiLSLBRUzuF4XhmV1Ta8PMwM7xwOwFGNUxEREWkWCirncLim26dDuB8dI/wBTVEWERFpLgoq51A7kLZTRACJYX7AyTEqJ/LLtP+PiIhIE1JQOYfaqcmdIv1JDK8NKqVsTM5lzMtLeeijLa4sT0REpFVTUDkHR4tKZADta4JKWkEZf/5+H9U2gyX7MsksKndliSIiIq2Wgso51E5N7hzpT2SAN35eFmwGbDqaB4BhwI+70l1ZooiISKuloFKPQ5lF/OXH/Ux6dQUZhRWAfYyKyWSifc04FYAwfy8AvtupoCIiItIUFFTqsT4plzeXHmJ/RhEWs4mfD0kg2M8TwDFOxdNiYu70gTXX55BdXOGyekVERForD1cX4I6u6BnNmkM5XNErmrHdIwnx83Kc6x0XzI+7M7hpcALDOoXTLz6YHccKWLg7g1uHtXdh1SIiIq2Pgko9ooJ8mFPTWnKqe0Z3pGtUAON6RgEwpU8sO44V8N3ONAUVERGRRqaun/Pk5+XBlL6xeHtYALiybwwAa4/kUFqpzQpFREQak4LKRUoM98fX04LVZpBdVOnqckRERFoVBZVGUDv7J7dUQUVERKQxKag0gpCaGUF5CioiIiKNSkGlEdS2qOSVKKiIiIg0JgWVRhBaM305V0FFRESkUSmoNILQmq6f/NIqF1ciIiLSuiioNIJQDaYVERFpEgoqjUBjVERERJqGgkojCNEYFRERkSahoNIIwmqCisaoiIiINC4FlUYQ6m8fTKsxKiIiIo3LpUHl+eefx2QyOX306NHDlSVdkNrpyXkllRiG4eJqREREWg+X757cu3dvFi9e7Hjs4eHyks5bbVCpthkUV1QT6OPp4opERERaB5enAg8PD2JiYlxdxkXx9bLg62mhrMpKXkmVgoqIiEgjcfkYlYMHDxIXF0enTp2YPn06KSkpZ7y2oqKCwsJCpw93Ubvom8apiIiINB6XBpVhw4Yxb948fvjhB+bOnUtSUhKjR4+mqKio3utnzZpFcHCw4yMhIaGZKz6z2kXftDGhiIhI4zEZbjT6Mz8/n8TERGbPns3dd9992vmKigoqKiocjwsLC0lISKCgoICgoKDmLPU0//fOelYezGb2zf25YWC8S2sRERFxZ4WFhQQHBzfo77fLx6jUFRISQrdu3Th06FC95729vfH29m7mqhpGi76JiIg0PpePUamruLiYw4cPExsb6+pSzluYNiYUERFpdC4NKk888QTLly8nOTmZNWvWcP3112OxWJg2bZory7og2phQRESk8bm06+fYsWNMmzaNnJwcIiMjGTVqFOvWrSMyMtKVZV2Quou+iYiISONwaVD5+OOPXfnlG5Vm/YiIiDQ+txqj0pKFOVpUNEZFRESksSioNJIQLfgmIiLS6BRUGklYTddPfmklO47l87O5a1hzONvFVYmIiLRsCiqNpHYwbZXV4JGPt7HpaB4fbUh1cVUiIiItm4JKI/H1suDjaf92JmWXAHA8r9SVJYmIiLR4CiqNqHZAba3j+WUuqkRERKR1UFBpRLVTlGODfQDILKqgotrqypJERERaNAWVRtQ/IQQPs4lZN/TFx9OMYUBafrmryxIREWmxFFQa0YtT+7D26fGM7R5FuxBfQN0/IiIiF0NBpRFZzCYiA+27O8eH+gFwTANqRURELpiCShNpF1rTopKnFhUREZELpaDSROJrgsoxBRUREZELpqDSRGrHqBzTGBUREZELpqDSROLV9SMiInLRFFSaSO1g2vTCcqqtNhdXIyIi0jIpqDSRyABvvCxmrDaD9EKtpSIiInIhFFSaiNlsIi7EvkKtBtSKiIhcGAWVJqQpyiIiIhdHQaUJxYfYx6lodVoREZELo6DShNo51lLR6rQiIiIXQkGlCWm/HxERkYujoNKEEsLsXT+HMosxDMPF1YiIiLQ8CipNqF98MH5eFjIKK9iWmu/qckRERFocBZUm5ONpYULPaAC+3ZHm4mpERERaHgWVJnZ1v1gAvtuZhs2m7h8REZHzoaDSxMZ0iyTQ24O0gnK2pOS5uhwREZEWRUGlifl4Wriil7p/RERELoSCSjO4ur+9+2fBzjRtUCgiInIeFFSawagukYT6eZJVVMErP+53dTkiIiIthoJKM/DyMPP/ru8LwD9WHOGHXeoCEhERaQgFlWZyZd9Y7h3dEYAnPt2hZfVFREQaQEGlGT01uQd92wVTXFHN4j0Zri5HRETE7SmoNCMPi5mB7UMAyCqucG0xIiIiLYCCSjOLDPQGIKtIQUVERORcFFSamYKKiIhIwymoNDNHUFHXj4iIyDkpqDSzyAAfQC0qIiIiDaGg0sxqW1Syiyu1SaGIiMg5KKg0s/AALwCsNoO80koXVyMiIuLeFFSamafFTJi/PaxonIqIiMjZKai4QGSAZv6IiIg0hIKKC2iKsoiISMMoqLiAgoqIiEjDKKi4gIKKiIhIwyiouIBjjIoG04qIiJyVgooLqEVFRESkYRRUXEBBRUREpGEUVFzgTPv9/GdtMk99toOKaqsryhIREXE7Hq4uoC2qHaOSX1pFRbUVbw8L5VVW/rhgLxXVNkZ0CWfqJe1cXKWIiIjrqUXFBYJ9PfG0mADIKbYvo78xOZeKahsAX2874bLaRERE3ImCiguYzSYiTlmddtXBbMf55QeyyCvRPkAiIiIKKi5y6oDalTVBxWI2UW0z+G5XmstqExERcRcKKi5Sdy2V7OIK9qQVAnDPqI4AfKXuHxEREfcJKi+99BImk4lHH33U1aU0i7otKqsP2VtTesYGccfIDphMsCEplxP5Za4sUURExOXcIqhs3LiRf/zjH/Tr18/VpTSb2qCSlF3iGJ8yumsEscG+DO0QBsD3u9JdVp+IiIg7cHlQKS4uZvr06bz99tuEhoa6upxmEx/qC8CXW4/z2ZZjAIzqEgHA2O5RAGxKznVNcSIiIm7C5UFlxowZXHXVVUyYMOGc11ZUVFBYWOj00VJdN6AdD4ztjLeHGcMALw8zQzvaW1IGtg8BYEtKHoZhuLBKERER13Lpgm8ff/wxW7ZsYePGjQ26ftasWbzwwgtNXFXz8Paw8NTkHtw2PJEP1h2lV2wwPp4WAPrFh+BhNpFRWMHx/DLiQ/1cXK2IiIhruKxFJTU1lUceeYQPP/wQHx+fBj3n6aefpqCgwPGRmpraxFU2vdhgX56c1IOr+sU6jvl6WegVFwTAlpR8F1UmIiLiei4LKps3byYzM5OBAwfi4eGBh4cHy5cv529/+xseHh5Yrafvd+Pt7U1QUJDTR2s1sL19vM6Wo3kurkRERMR1XNb1M378eHbu3Ol07M4776RHjx489dRTWCwWF1XmHgYlhjJvTTJbUhRURESk7XJZUAkMDKRPnz5Ox/z9/QkPDz/teFs0MNHeorLnRCFllVZ8vdp2cBMRkbbJ5bN+pH5xwT7EBPlQbTPYcSzf1eWIiIi4hEtn/Zxq2bJlri7BbZhMJgYmhvDdznQ2p+QxrFO4q0sSERFpdmpRcWO1A2q3auaPiIi0UQoqbqx3XDAA+9Jb7sJ2IiIiF0NBxY11iw4AIDW3jNLKahdXIyIi0vwUVNxYeIA3EQFeABzKLHZxNSIiIs1PQcXNdY0KBOBAhoKKiIi0PQoqbq62++dgRtEZr6my2pqrHBERkWaloOLmukbbW1T21xNUDMPgP+uO0v+FhTz71a7mLk1ERKTJKai4uW41QeXgKV0/xRXVPPjhFp6Zv4vSSivf7Ux3RXkiIiJNSkHFzdV2/RzPL6O44uTMn9kLD/D9rnQ8LSZMJsguriCzqNxVZYqIiDQJBRU3F+LnRVSgN3BynEqV1cb8bccBeGPaADpF+AP2fYFERERaEwWVFuDU7p8VB7LILakkIsCbCT2j6VWzMNyeNAUVERFpXRRUWoCuNd0/tQNqv9xqb025tn8cHhYzvWKDANibZj9fUFbF5qO52GyGC6oVERFpPG61KaHUr7ZF5UBGEUXlVSzakwHA9QPaAdAz1n5+z4kCAB76aCsrDmTRPyGE/3ddH/q0C3ZB1SIiIhdPLSotQO2A2u2p+bzwzR4qqm10jvSnTzt7S0qvOPt/j2SXcCizmBUHshzXX/vmKhbu1owgERFpmRRUWoAeMUEEentQWF7NZ5uPAfbWFJPJBEBUoA8RAd4YBvzlx/0A9E8IYWz3SGwGjueIiIi0NAoqLYC/twffPzqaX0/uTr/4YLpHB3LzkASna2q7f36oaT35+ZAE7hvTCYC92n1ZRERaKI1RaSHiQ/14cGwXHhzbpd7zveKCWHkwGwBPi4kpfWKoHUubmltGUXkVgT6ezVWuiIhIo1CLSitRO/MHYGz3KEL8vAjz9yI6yL4Gy4Gz7BUkIiLirhRUWonecSeDytRL4hyf96wJMHvSFFRERKTlUVBpJTpGBNA50p/EcD/G94h2HO8RYw8q+7QYnIiItEAao9JKWMwmvn9kDDbDwMfT4jheO8h2r4KKiIi0QAoqrYiXx+kNZLVdP/vTi7DZDMxmU3OXJSIicsHU9dPKdYzwx8tipqTSyrG8MleXIyIicl4UVFo5T4vZsVeQNi0UEZGWRkGlDXAMqNXCbyIi0sIoqLQBtQNq92mKsoiItDAKKm1A7YBaLaUvIiItjYJKG9Ajxt6icjSnlJKKahdXIyIi0nAKKm1AeIA3UYH2pfT3ayl9ERFpQRRU2ogetd0/mvkjIiItiIJKG9EzRgNqRUSk5VFQaSN6qkVFRERaIAWVNqJH7RTl9CIMw3BxNSIiIg2joNJGdI4MwNNioriiWkvpi4hIi6Gg0kZ4Wsx0idJOyiIi0rIoqLQhjgG16RpQKyIiLYOCShtSO6BWe/6IiEhLoaDShtQOqN2rKcoiItJCKKi0IbW7KCfnlGgpfRERaREUVNqQyEBvYoN9MAzYfDTP1eWIiIick4JKGzO6awQAKw5knfEawzCw2rTWioiIuJ6CShszumskACsOnjmoPPTRVkb/+ScKy6uaqywREZF6Kai0MaO6RGAywYGMYtILyk87bxgGi/ZkcKKgnF3HC1xQoYiIyEkKKm1MqL8X/eJDgPpbVfJKq6iotgFoBVsREXE5BZU26LKzjFNJKzgZThRURETE1RRU2qAx3ezjVFYdyj5t0Gzd7qBjeaXNWpeIiMipFFTaoP4JIQR6e5BfWsWaw9lO59KcgopaVERExLUUVNogT4uZ8T2jALjn/U38b2Oq41zdFpXjCioiIuJiCipt1AvX9mFcjygqqm38+vMd/HttMgAn6oxRSSsoo8pqc1GFIiIiCiptVrCfJ/+6bTB3jewIwHc70wDnFhWbQb1TmEVERJqLgkobZjabuH5AOwAOZhQDpweTVA2oFRERF1JQaeO6RAVgMkFOSSU5xRWOwbTtw/wAjVMRERHXUlBp43y9LCSE2kPJxuQ8yqqsAAxODAU080dERFzLpUFl7ty59OvXj6CgIIKCghg+fDjff/+9K0tqk7pFBwAnV6oN8/eic5T92JmCyhtLDnLTW2sorqhuniJFRKRNuqCg8v7777NgwQLH41//+teEhIQwYsQIjh492uDXiY+P56WXXmLz5s1s2rSJcePGMXXqVHbv3n0hZckF6hodCMDy/fagEhPkQ3yoL1D/om8FZVW88dMhNibnse5wTvMVKiIibc4FBZU//elP+Pra/5CtXbuWOXPm8PLLLxMREcGvfvWrBr/ONddcw5VXXknXrl3p1q0b/+///T8CAgJYt25dvddXVFRQWFjo9CEXr7ZF5Xi+vfUkNtiH+JruoNoWlcpqG4ZhX8V24e50KmumLdddcl9ERKSxXVBQSU1NpUuXLgDMnz+fG2+8kfvuu49Zs2axcuXKCyrEarXy8ccfU1JSwvDhw+u9ZtasWQQHBzs+EhISLuhribOuUYFOj2OCfUioaVFJLyznp30Z9Hn+R174Zg8A3+5Ic1x7QtOXRUSkCV1QUAkICCAnx97kv3DhQq644goAfHx8KCs7v//D3rlzJwEBAXh7e3P//ffz5Zdf0qtXr3qvffrppykoKHB8pKam1nudnJ/OkfaZP7Vig32ICPDGy8OM1Wbw0H+3UlltY96aZH7al8HqQyeX3U/LV4uKiIg0HY8LedIVV1zBPffcw4ABAzhw4ABXXnklALt376ZDhw7n9Vrdu3dn27ZtFBQU8Nlnn3H77bezfPnyesOKt7c33t7eF1KynIWvl4X2YX4czbGPR4kN9sVsNhEf4suR7BJKKq2YTfYF4B74YAvVdTYyPJGvFhUREWk6F9SiMmfOHIYPH05WVhaff/454eHhAGzevJlp06ad12t5eXnRpUsXBg0axKxZs+jfvz+vv/76hZQlF6Fu909ssA8A7Wq6f7w8zPz7rmEE+nhQUW0fmzKhZq+gExqjIiIiTeiCWlRCQkJ48803Tzv+wgsvXHRBNpuNioqKi34dOT/dogNYvDcDsI9RARjWMYyVB7P5/VU9GdU1gsev6MbzNeNU7h3dicV7M8koLMdmMzCbTWd8bRERkQt1QUHlhx9+ICAggFGjRgH2Fpa3336bXr16MWfOHEJDQxv0Ok8//TRTpkyhffv2FBUV8d///pdly5bx448/XkhZchG6RddtUbG3pMy4vAu3DGlPZKC9u+0XlyZyOKuEyEBvBiWGYjZBldUgu7iCqCAfl9QtIiKt2wV1/Tz55JOOqcE7d+7k8ccf58orryQpKYnHHnuswa+TmZnJbbfdRvfu3Rk/fjwbN27kxx9/dAzOlebTKy4IgMhAb3y9LACYTCZHSAHwsJh58bo+PDy+Kx4WM9E14eS4BtSKiEgTuaAWlaSkJMdg188//5yrr76aP/3pT2zZssUxsLYh3nnnnQv58tIEukUH8tINfR17/DREbLAPaQXlpBWUM6AJaxMRkbbrglpUvLy8KC21zxBZvHgxEydOBCAsLEyLsLVgPx/anhFdIhp8fWyIvYvohFpURESkiVxQi8qoUaN47LHHGDlyJBs2bOCTTz4B4MCBA8THxzdqgeK+2tUElTQt+iYiIk3kglpU3nzzTTw8PPjss8+YO3cu7dq1A+D7779n8uTJjVqguK/aacxqURERkaZyQS0q7du359tvvz3t+KuvvnrRBUnLUTs7SMvoi4hIU7mgoAL2vXnmz5/P3r17AejduzfXXnstFoul0YoT9xYXYm9R0TL6IiLSVC4oqBw6dIgrr7yS48eP0717d8C+YWBCQgILFiygc+fOjVqkuKe4mjEqWcUVVFbb8PK4oJ5EERGRM7qgvywPP/wwnTt3JjU1lS1btrBlyxZSUlLo2LEjDz/8cGPXKG4q3N8LLw8zhgEZher+ERGRxndBLSrLly9n3bp1hIWFOY6Fh4fz0ksvMXLkyEYrTtybyWQiNtiHozmlnMgvI+E81mARERFpiAtqUfH29qaoqOi048XFxXh5eV10UdJyxAVrirKIiDSdCwoqV199Nffddx/r16/HMAwMw2DdunXcf//9XHvttY1do7ix2BAtoy8iIk3ngoLK3/72Nzp37szw4cPx8fHBx8eHESNG0KVLF1577bVGLlHcWdco+2aG21PzXVuIiIi0Shc0RiUkJISvvvqKQ4cOOaYn9+zZky5dujRqceL+Lu1kH6e0PikXm83AbDa5uCIREWlNGhxUzrUr8tKlSx2fz549+8IrkhalT7tg/L0sFJRVsS+9yLELs4iISGNocFDZunVrg64zmfR/1G2Jp8XM4A5hLD+QxbojOfUGlczCcv7200HuHd2JxHB/F1QpIiItVYODSt0WE5G6Lu0U7ggqd43qeNr515cc5MP1KdgM+NP1fV1QoYiItFQXvIS+SK1Tx6nUNqrVtq6tPJgNQGpuqUvqExGRlktBRS5a3XEqP+5O57XFB/HxNPPZAyM4kV9GSk1AOZ6nKcwiInJ+FFTkotUdp/LAh1scx5fszSCrqMLx+Hh+GYZhaByTiIg0mHaRk0Zxaadwx+c+nvZ/Vh+uT2FFTbcPQEW1jeziymavTUREWi4FFWkUV/aNIdjXk0m9o/lqxihMJvvYlBUHsgCoXV5FK9iKiMj5UNePNIrEcH+2PnOFY8G3y7pFsmx/FhXVNkL9POkQ4c/WlHyO55VxSUKIa4sVEZEWQy0q0mjqrko7fVii4/NRXSNJCLXvrHw8XzN/RESk4RRUpElc3j2S2GD7hoVjukbQLtS+y/L5zvwxDKPRaxMRkZZDQUWahIfFzBvTBvDQuC5cN6Ad7UJqgsp5jFF56KOtXPbKMnKKK859sYiItEoKKtJkBncI4/GJ3fG0mB0tKsca2KJiGAYLd6eTklvKp5uPNWWZIiLixhRUpFnEn2eLSlFFNRXVNgA+3pCiLiARkTZKQUWaRW2LSlF5NYXlVee8vu5Ccck5paw9ktNktYmIiPtSUJFm4eflQaifJ1D/gNqPN6Rw6Z+W8MUWezdP3aAC8NGG1KYvUkRE3I7WUZFm0y7Ul7zSKo7mlPDM/F0czirmhoHxlFdZ+XB9CgDf7UzjhoHxjqASEeBFdnElP+5KJ7ekkjB/L1fegoiINDO1qEizqZ3589rig2w6mkdeaRXvrEpyhBSAE/nlwMkWlWGdwunbLphKq40fd6c7rksrKCOvRMvxi4i0dgoq0mzahdgXfduXXgTAbcMTGd8jinYhvjx+RTfAHkAAsmqmJEcGeNM/IbjmnD3EFFdUM+Gvy7lh7ppmrV9ERJqfun6k2dQOqAXoHOnPs1f3wsNiz8oFpVX8ddEB8kqrKK+yOlpUIgO9qaiyAjhaUFJzSymptJKUXUJ5lRUfT0sz34mIiDQXtahIs6nt+gH43VU9HSEFIMjXAz8ve+BIKyh3Ciq141JyS+1BJbdOl0+uun9ERFo1BRVpNoM7hBIR4M21/eO4vHuU0zmTyURMzZL7afllTkEltCao1Lao5CioiIi0Ger6kWYTEeDNxt+NB+zB5FRxwb4cySrhREG50xgVj5rNDmtDSW6dJfVzFFRERFo1tahIszKZTPWGFMCxieHxvDJHKIkK9CbUr6brp6S+rh/n9VbSCsq47JWlvLX8cKPXLiIizU9BRdxGbM0Ylj1pBVhtBiYThPl7Ocao5JVWYhiGUytKTrFzi8rawzkczSnlq20nmq9wERFpMgoq4jZqW1R2HCsAIMzPCw+L2RFUqqwGxRXVZx1MWzu2JbOwvDlKFhGRJqagIm6jNqjUrpcSGegNgI+nxTEjKK+k6qyDaWuDSk5JJVVWW5PXLCIiTUtBRdxGXJ3py3AyqACOcSo5JRVO4eTUwbRZdQbanrpfkIiItDwKKuI2aqcn14oMOBlU6o5TyTtLi0p2naCSqaAiItLiKaiI2wjy8STA++SMeacWlZqgkl1cSV7pubt+QONURERaAwUVcSuxdVpV6gaVMD9PAJKyS7AZJ6/PKXZuNakbVDLUoiIi0uIpqIhbia0zTqW+FpVDmcUAWGoWgSssr3YMmq2stpFXWuV4TpZaVEREWjwFFXErsUF1WlTqjlGpGUx7uCaoxIf6UpNV6iyt79yCklGoFhURkZZOQUXcSmzIGbp+AuxBJTmnBLAvx39yJpA9qJw6yyezSC0qIiItnYKKuJW44JNdPxH1tKjUjk+pu2Jt7YDa7GK1qIiItDYKKuJWaqcoe1pMBPt6Oo7XjlGpFV4nqJzaohIdZA84mp4sItLyKaiIW+keE4inxUT3mEDM5pObF4adElTC/L0Ir+kOqp35UxtUescF24+XVFCt1WlFRFo0j3NfItJ8ooN8WPSrywjx83Q6XjsepVaYvxeF5fYZPrmntKh0jwlk+YEsrDaD7OLK0xaSExGRlkMtKuJ2OkT4E3JKMDk1uIQHeBHub+/icXT91LSsRAd6O2YMaUCtiEjLpqAiLYKnxew0ZiXM39vR9ZNb7NyiEhnoQ1TNOBUNqBURadlcGlRmzZrFkCFDCAwMJCoqiuuuu479+/e7siRxY3XHqYTXO+vH/t/IQG+iAu3dPWpRERFp2VwaVJYvX86MGTNYt24dixYtoqqqiokTJ1JSUuLKssRNhfrVbVGpO+vHeTBtRICXWlRERFoJlw6m/eGHH5wez5s3j6ioKDZv3syYMWNcVJW4q7otKmH+XhSVVwP2FpXSymqKK+yPIwO9ia5pUclSi4qISIvmVrN+CgoKAAgLC6v3fEVFBRUVJ/8PubCwsFnqEvdQO/PH38uCj6fFEVzyy6ocLSc+nmYCvD3UoiIi0kq4zWBam83Go48+ysiRI+nTp0+918yaNYvg4GDHR0JCQjNXKa5UG0xql9Ov7QoyDDiYUQTYW1NMJlOdRd9Ob1FJKyhj3F+X8fzXu5ujbBERuQhuE1RmzJjBrl27+Pjjj894zdNPP01BQYHjIzU1tRkrFFdzBJWaackeFrNj2vLetJqgUjMt2TGYtp4WlbdXJHEkq4R5a5LZn17U5HWLiMiFc4ugMnPmTL799luWLl1KfHz8Ga/z9vYmKCjI6UPajnah9n2A4kNP7geUGO4PwNzlh4CT+wPVdv1kF1dQWlntuL6grIpPNqY4Hv992aGmLVpERC6KS4OKYRjMnDmTL7/8kp9++omOHTu6shxxcxN7xfDnG/vy9JQejmMvTu1NmL8X5VX2pfJrd1yODPCmfZgfNgM+2Xiy5e2jDSmUVFodXUPfbD9BcrZmmYmIuCuXBpUZM2bwwQcf8N///pfAwEDS09NJT0+nrKzMlWWJm/LyMHPLkPbEh/o5jvWLD+Gz+4eTEGZvZUkMt58zmUzcN6YTAG+vOEJltY3KahvvrU4C4ImJ3RnXIwqbAXOXHW7mOxERkYYyGYZhuOyLm0z1Hn/vvfe44447zvn8wsJCgoODKSgoUDdQG5dbUsmy/ZlM6h2Dv7d9Mlt5lZXRLy8lq6iCP9/Yl6TsUt5afpioQG9WPnU5u44XcuPcNXhaTGz47QTHDs1Wm4HZdOZ/nyIicnHO5++3S6cnuzAjSSsT5u/FDQOdxzf5eFq4e1RHXvp+H09/sRNbzT+3B8d2xtvDwqDEULpHB7I/o4g1h3O4ql8saw5nc9e8jVRU2/DztHDT4ASev7a3C+5IRETATQbTijSV6cPaE+Tjgc2wr7/y15v6c/uIDo7zI7qEA7D6cDYAH65PobzKhmFASaWV99cmk1moReNERFxFQUVatUAfT1695RJ+PiSBBQ+P5sZB8U5dOiM7RwCw5lA2ldU2lu/PAmDenUPoHx+MYcB3O9NcUruIiCioSBswvmc0L93Yjw4R/qedG9YpDIvZRHJOKZ9vOUZxRTWRgd6M6RrJNf3jAPh2h4KKiIirKKhImxbo40n/+GAA/rrQvnP3hJ5RmM0mruoXC8Cmo3mcyNdMNBERV1BQkTZvZBd79092cSUAV/SKBiA22JchHUIBdf+IiLiKgoq0eSNqxqkA+HlZnB7Xdv98o+4fERGXUFCRNm9gYgg+nvYfhTFdI/HxtDjOTekTi9kE21PzWbY/01Ulioi0WQoq0uZ5e1gY3TUSwDEupVZkoDc3D7bv0j3jwy3sOl7Q7PWJiLRlLl2Z9mJpZVppLLkllew8XsCYrhGnrUhbWW3jznkbWH0oh8hAb76ZOYqYYB8XVSoi0vKdz99vtaiIYF/Z9rJukfUum+/lYWbuLwbRPTqQrKIKx35BIiLS9BRURBogyMeTRyd0BezrqrTghkgRkRZFQUWkgS7vEYW/l4Xj+WVsScl3dTkiIm2CgopIA/l4WpjYOwaAb7afcHE1IiJtg4KKyHm4pr99VtC3O9Kw2tT9IyLS1BRURM7DqC6RBPt6kl1cwfojOa4uR0Sk1VNQETkPXh5mpvSxd/98vuW4i6sREWn9FFREztNNNQvAfbXtOEdzSjAMg+e/3s11c1aTV1Lp4upERFoXBRWR8zQoMZSx3SOpthm8tvggn20+xrw1yWxLzef9tcmuLk9EpFVRUBG5AE9M7A7A/G3Hefar3Y7j/1l7lPIqq9O12cUV5BRXNGt9IiKthYKKyAXo0y6YKX1iMAwoq7IytGMY7UJ8ySmpZP7Wk2NXyiqtTH5tJVNeX0lReZULKxYRaZkUVEQu0GNXdMPTYiLIx4NXb7mEO0d2AOBfq5IcK9duP5ZPdnEFmUUVfLIx9Yyv9cdv9zDjwy0cySpujtJFRFoMBRWRC9Q1OpAFD4/mu0dG0y7El5uHJBDg7cGhzGKWH8gCYEtKnuP691YnU221nfY66QXl/GtVEgt2pjH5tZW8uuiAlugXEamhoCJyEbpFBxIf6gfY9wP62aB4AL7ZngbA1jpL7R/PL+P7Xemnvca6mvVYPC0mKq02Xl9ykIV7Mpq4chGRlkFBRaQRTewdDcDyA5nYbAZba1pULusWCcDbK4+c1lpSG1TuHNnREXQ2H81DREQUVEQa1eDEMAK8PcguruS7XWlkF1fiZTHz0o198fYws+NYAduPFTg9Z21NUBneKZwhHUIB2HX85DWpuaUUlGogroi0TQoqIo3Iy8PMqC4RALy2+CAAveKCiA32ZXRXe6vK1jrjVk7kl3E0pxSL2cTgDqH0jgsGYPeJQgzD4GhOCRNmL+fu9zc2852IiLgHBRWRRnZ5D3sgOZRpn8EzsL29laR3XBAAe04UOq6t7fbp0y6YQB9PukYH4GkxUVBWxfH8MpbszaSi2samo3kUanqziLRBCioijWxs9yinxwMTQwB7ywrAnrSTQWXtYXtQubRTGADeHha6RgUCsOt4IWsOZzuurdsdJCLSViioiDSy6CAfesUGOR4PqGlRqT12MKOYymr7NOV1SSfHp9SqbXnZfiyfdUdyHccVVESkLVJQEWkCtd0/0UHexAX7ABAf6kugjweVVhuHs4o5lldKam5ZzfiUMMdz+7Szj1P5bPMxiiuqHcd3Hi9ERKStUVARaQI3Down3N+LWwYnYDKZADCZTI5WlT0nClmyNxOASxJCCPD2cDy3tkUlq8i+P1BEgBcAO4/lN1f5IiJuQ0FFpAl0igxg8zNX8FjN5oW16o5T+XbHCQCm9IlxuqZnbBA12Qawr68CkJxT6jSgtspq451VSRzLK22KWxARcQsKKiLNqLZFZdn+TDYm26cpX9Uv1ukaf28POob7Ox5f3S+W+FBfwHmcymebj/Hit3t4/uvdiIi0VgoqIs2otkXlcFYJAIMTQ4kN9j3tut4141TahfjSPsyPvjWPd9ZZLK52mvP6I7lYbdobSERaJwUVkWbUNSoQT8vJfp2rT2lNqVU7XfmKXtGYTCb6xtcElTotKrXrtBRVVLMvXQNtRaR18jj3JSLSWLw8zHSJCmRvWiEmE0zpW39QmTakPfGhfgytmQ1U26JSt+vncFax4/NNyXmOVW1FRFoTtaiINLPacSpDO4QRHeRT7zVms4nLukXi62UBoE9NCEnOse/7U1heRWbNrCCADcm59b6OiEhLp6Ai0sx+PjSBThH+PDy+a4OfE+rvRWK4HwBbU/Mc3T61NiXnnrYr87kczirmgQ82O7XMiIi4GwUVkWY2pEMYPz0xlpE1mxc21OBEezfQ5qN5dfYRCsHTYiKjsILU3LLzer2/LTnI97vS+cfyw+f1PBGR5qSgItJCDOlgX4p/Y3KuoxWkT7tgx/iVjefR/WOzGaw+ZN9HaFtqfuMWKiLSiBRURFqIwTVBZVtqPvvSigDoEhXAkJoBt3WDyq7jBfx14X7H6ran2pdeRHZxJQAHM4udluoXEXEnmvUj0kJ0jgwg1M+TvNIqR2tI58gA4oJ9+ceKIyzak8GlnY6TXVzBn3/YR5XVYN2RHD6+bzgWs8nptVYezHJ8bhiw41g+IzqfX1eUiEhzUIuKSAthMpkYVDNOpbpmgbcuUQFc2jmc+FBfckoqefSTbfxxwV6qrAZmE2xMzmPO0kOnvdaqmqDjURNg1P0jIu5KQUWkBakdpwIQ6O1BVKA3Ad4efPvQKJ6Y2I1wfy+8PMy8OLU3f725PwCvLznI5qMnu4XKq6xsSLI/vmFgOwC2K6iIiJtS149ICzK4ZjwKQKeoAMfOzCF+Xswc15X7xnSmvNpKkI8nAMv3ZzF/2wme+HQH3z8yGh9PCxuTc6mothET5MONA+P536ZjalEREbelFhWRFqRPuyC8Pew/tl0iA0477+VhdoQUgD9c14eoQG+Sskv4+zL7NORVB+3dPqO6RtA3PhiL2T69Ob2gvBnuQETk/CioiLQg3h4W+ieEAPbxKecS5OPJ89f2BmDuskO88uM+5q1JBmB01wj8vDzoFh0IwLbUvCapWUTkYiioiLQwT07qztX9YrllSEKDrp/SJ4ZxPaKoshrMWXqYimobl3ePZEof+z5DlyTY12H5Ystx/rpwP19sOdZktYuInC+NURFpYYZ0CHOsndIQJpOJF67tzabkXKqsBr+9qie/GNbeMb7lkoQQPtqQysI9GSzckwHAsE7htAvxbZL6RUTOh4KKSBuQEObHT0+MxcNsIsTPy+ncFb1i+M+6oxgGZBSWk11cyabkXNpd0s5F1YqInKSuH5E2IiLA+7SQAhDm78W3D41mwcOjmVoTTs5nOX4RkaakoCIiDrXrtGxKPjmw1mYzWLg7nXve38g7q5JcVZqItFHq+hERh9p1WvZnFFFQWkVeaSX3/nsTB2t2a166P4sJPaNIDPd3ZZki0oa4tEVlxYoVXHPNNcTFxWEymZg/f74ryxFp8yICvOkU4Y9hwOaUXP64YA8HM4sJ9PYgMdwPq83greWHXV2miLQhLg0qJSUl9O/fnzlz5riyDBGpo3aX5g/WpbB4byYmE8yfOZK/3GRfkv+zzcdIKyhzZYki0oa4tOtnypQpTJkypcHXV1RUUFFxctv6wsLCpihLpE0b0iGM/206xk/7MgG4sk8snSMD6BwJQzuGsSEpl3+uOMJz1/R2caUi0ha0qMG0s2bNIjg42PGRkNCwBa9EpOFOXaPlgbGdHZ/PvLwLAP9dn8Kaw9mO40XlVRiG0TwFikib0qKCytNPP01BQYHjIzU11dUlibQ6ieF+RAR4A3BZt0j6tAt2nBvdNYIx3SKpqLZx+7sbeG3xAab9cx19n1/Iyz/ud1XJItKKtaig4u3tTVBQkNOHiDQuk8nEjQPb4edl4bErup127p//N4ir+sZSZTV4bfFB1h7JAeCdVUlkFmljQxFpXC0qqIhI83j6yp7seG6iYwPEunw8LbwxbQAzL+9CuxBffjmmE/3ig6mstvHe6uRmr1VEWjcFFRGpl4flzL8ezGYTT0zqzurfjOPpK3vy0LiuAHyw9iiF5VVnfV2bTWNZRKThXBpUiouL2bZtG9u2bQMgKSmJbdu2kZKS4sqyROQ8je8RRdeoAIoqqnlvVbJjYO2u4wV8sO4oRTXhJa2gjAmzl3Pj3DUNDixWBRuRNs1kuHCo/rJly7j88stPO3777bczb968cz6/sLCQ4OBgCgoKNF5FxMU+33yMxz/dDkDHCH/8vCzsPmFfQqBnbBB/nz6QBz/cwt40+7GP7r2U4Z3Dz/h61VYbj/1vO0v2ZvDVzFF0iQpo+psQkWZxPn+/XbqOytixYzWlUaSVuPaSODYdzeXzLcdJyi4BwMtixtvTzN60QibMXu7UOvL5lmNOQaXaauM/644SEeDNxN7R/O7LXXy9/QQAP+xKY2ZN95KItC0ubVG5WGpREXE/xRXVLN2XSXFFNZN6x1BYVsVt724gJbcUbw8zT07qzh8X7MXfy8LG30/Az8v+/0vvrkriD9/uASDA24PiimrHa47uGsF/7h7mkvsRkcZ3Pn+/NZhWRBpVgLcH1/SPY9rQ9oT5e9Ehwp/PHhjOPaM68v5dQ7l7VEfah/lRUmll4e4MAEoqqpmz9BAA/l4WR0i5b0wnADYfzaPaanN8jfzSSj5cf5SPNqSoVVakldPuySLS5KICffj91b0cj28Y2I7XFh/k8y3HuG5AO+atSSanpJLEcD9+eGQMyw9k4edlYVSXCD7ZmEpBWRW7ThTSMzaQ577azRdbjlNZE1z2pxfx3DW9MJlMrro9EWlCalERkWZ3w4B4AFYdyuYP3+xx7Mj82BXd8PWyMLlPDGO6RWI2mxxL+m9IyuHTTcf4eGMqlVYbnSP9AZi3Jpk/fLtHLSsirZSCiog0u/bhfkzqHY1hwLurkygqr6Z7dCDX9Is77dphHe1BZe3hHN5ZlQTA01N6sOTxsbx0Q18A3lud7Bh4KyKti4KKiLjE36YN4K1fDOSmQfH0bRfM/7u+D2bz6d03Q2uCytL9WSRllxDk48EvLk0E4OdD2zs2SvzP2qMAGIbB/zamsvpQ9mmvJSItj8aoiIhLeHtYmNwnlsl9Ys96Xe+4IPy8LJRWWgH4xaWJ+Huf/NX1f8MTmbv8MJuO5nEgo4gDGUX8+vMdeHuYWfXUOCIDvZv0PkSkaalFRUTcmofFzKDEUMC+LssdIzo4nY8O8mFCzyjA3gU067t9AFRU2xxdRSLScimoiIjbu7y7PYjcOCieqCCf085PG9oegI82pHA8vwxfTwsA/1mbTH5p5WnXl1dZeeTjrcz4cAtrDmefcyButdXGxuRc/rs+hTeWHCSzULtEizQXdf2IiNu7bXgiXaICGNYprN7zY7pG0i7El+P5ZQC8dGNf3lp+hL1phby3OplfXdHNca1hGPz2y518tc0++HbBzjT6tgvm7dsGExN8eggqKKvijvc2sDUl33HsREE5s2oG8opI01KLioi4PQ+LmTHdIvH2sNR73mw2Mf1Se6vKoMRQru0f5xhk+/bKIzz2yTbeWZXE+iM5/GtlEl9sOY7ZBFMvicPX08LO4wXc/u4GCsqcd34uKKvitnfWszUlnwBvD/rFBwP2qdKnOphRxJylhyivsjbmrYu0eWpREZFW4d7RnYgK9OHy7pGYTCYm94nhkoQQtqXm88XW43yx9bjT9b+9sif3jO5Eam4pN85dw/6MIu799yb+fddQfDwtlFdZue3dDWw/VkConycf3nMpscE+DHhxEYezSsgrqSTU3wuA0spq7nhvI8fzyzCZ4MGxXVzxLRBpldSiIiKtgqfFzM8GxRMeYJ/lYzGb+Pi+S3n3jsE8dkU3JvaKJq6ma+fGgfHcPaojAAlhfsy7cyiB3h5sSMrlV59sw2oz+PMP+9iemk+Inyf/vfdSesUFEerv5VhobvPRPMfXfn3JQUe308cbUrHZDApKq7j5rbU8//Xu5vw2iLQ6alERkVbLx9PCuB7RjOsR7ThWWlmNr6fFacn9XnFB/OO2Qdzx7ka+35XO7e9uYFXNOiyv3nwJPWNPbpo2ODGMw1klbDqax4Re0exLL+SdlfbZRZ4WEym5paw+nM3y/VlsSM5lQ3Iu91/Wud7xLyJybmpREZE2xc/Lo959gUZ0juDVWy7BZMIRUu4c2YHLe0Q5XTeog32q9OajuRiGwe++3EW1zWBS72jH7KNXFx3g/bXJjuf8uDv9nHVVVtvqnaEk0tYpqIiI1LiqXyzPX9MbgL7tgvnNlB6nXTO4Zk2X7ccK+Hr7CTYfzcPX08Lz1/Z2BJUtKflUWQ3HNOnvd6Wd82vf/8FmLp21hO2p+Y10NyKtg4KKiEgdt4/owLInxvLZA8PrnWXUMcKfcH8vKqtt/P7LXQDcO6YTscG+9IwNYkD7EADMJpgzfQAAG5JyySqqOOPXTC8o56d9mZRX2fj9/F1Ybc7runy8IYXPNx9rpDs8Kbu4goc+2sr/NqVqU0dxWwoqIiKn6BDhf8ap0CaTiYE1rSpFFdWE+Xtx7+iOjvO/HNMJsAeecT2i6RcfjM2AhXvSWbI3g8f/t51DmcVOr7loz8muoZ3HC/jvhhTH48V7MvjNFzt5/NPtjgG7jeWj9Sl8s/0Ev/5sB3fO20h6gRayE/ejoCIicp5qu38AHhrXhUAfT8fjyX1i2fDb8Tx7dS8AptTsZfTXhQe4+/1NfL7lGD97aw1bU07OGvpxdwYAPWICAXj5h32kF5RTWF7F7+fvcly3qAFjXU5VXmXl2a928cnGlNPOrTiY5fh82f4spv9rHTabWlbEvSioiIicp9FdIzGZoEO4H7cOa3/a+aggH8eA3Sl9YgDILbEPlG0X4kt+aRW3vr2elQezKCitYt0R+wJyc6YPpHdcEEXl1Ux6bQX3vr+J9MJyasf+LtyT4fR1CsurePDDzXyw7ugZa/3jgj38e+1RnvlqN8UV1U7P3VKz2u57dwzB38vC4awSdp0ouLBvikgTUVARETlPveKCmP/gSP53f/3jWOrqEOHP2O6RhPp58s//G8Six8YwplskZVVWfvmfzby59CDVNoPu0YF0jgzgb9MG0DM2iIKyKtYn5QLw5xv7AbA+KddpZtDbK47w3c50Zn23t94VcX/YlcYH6+wtKZXVNpbvP9mCsuZQNlabQacIfy7vEcXorpEALNmbeXHfHJFGpqAiInIB+ieEEBXYsLVR3rtjCBt/N4GJvWPw8/LgX7cNZmSXcEorrbxdswbLpN72tV46RwbwzcyRvDi1Nwlhvjw8rgs3D06gR0wgVpvBT/vsQSK/tJL3VicDUFJpZdXBbKeveSK/jF9/tgOAiJpF8H6o03W0/ID9+jHd7AFlXM0O1LWvL+IuFFRERJqYyWTCw3Ly162Xh5m/Tx9E16gAx7GJvWMcn3tYzPzf8A6s/PU4HpvY3en8wprxLP9ameTUlfPDKeNXXvhmN4Xl1fRPCGHOrfbZR0v3ZVJRbcUwDFYcsLeujOkWAZzcoXrn8QIyzrE79A+70vjN5zsoKq8663UijUFBRUTEBYJ9PXn3jiEkhPkytEMYveOCznr9xF72FpflB7KYv/U489YkA/ZF6QAW7cmgymoDYOXBLH7cnYHFbOKVn/VjSIcwogK9Ka6oZs3hHI5kl3A8vwwvi5lLO4UDEBnoTf+EEMAeaM4kr6SSx/+3nY83pvLa4oMX8R0QaRgFFRERF0kI82PZE5fzyS8vrXe13Lp6xwXRLsSXsiorj36yjeKKanrFBvG7K3sS7u9lH9NyJJfKaptjf6Hbh3egW3QgZrOJiTVdS9/vTOPLLfYNGgd3CMXP6+ROKuNrVuFdUieopOSUcsXs5fx14X4A/rnyCCWV9vEw/16bTFJ2Sb31frQhhev/vpo9Jwov5FtzVgczili6L5OtKXnkFJ95fZqLcSK/jLwSrRTsDrTXj4iIC1nMZw8otUwmE3+8vg8frjtKSYUVA4MnJ/XAw2Lmil7RfLwxlY83pvD19uMcziohIsCLR6/o6nj+pN4xfLAuhf9tOrlw3LhTtgcY1yOK2YsOsOpgNuVVVnw8Lby+5CAHM4s5+NMhzCYT79e05LQL8eV4fhl/+m4vtw/vwBdbjjGmWyTXDWhHTnEFL367h9JKK7e9u55P7x9Bxwj/i/5eZRaV89L3+/hiy8mdsD0tJr59aDTda6Z2N4a0gjKumL2cdqG+/PjomHOGyLNJzS3FZhgkhl/8/bdVCioiIi3E5d2jHGNJ6prUJ4aPN6by7Y6TS/X/ZkpPguqs73Jpp3DC/b3IKakkyMeD6ZcmcseIDk6v0zsuiNhgH9IKypm3Jpmr+8Xy1baToeD1Jfaunn7xwfzlpv5MeX0li/ZksKhm2vTX20/QKdKfb7afoLSm1SW7uJJf/Gs9L17Xm95xwaxPyuWj9SlU22zMuXUgUUENG5C8P72In721hqJy+7icHjGBpBWUU1BWxScbU3n2Gvu6NdtT80kI8yPM3wuw73L92eZjgIGPp4Vbh7ana7RzqCmvsnIgo4h+8SEALNiRRkmllQMZxRzLKyMhzK9BNZ6qtLKaqXNWU221sfo345zW25GGU1AREWnhRnaOICbIh/TCcoZ2DOOByzqftpmip8XMB/cM43BWMeN6RDl1+dQymUz86opu/PqzHcxedICNSblU2wxGdgknPsSPTzalAvCrK7rRLTqQ/7s0kXlrkvH1tJAQ5suBjGIe+XgbJ2pW0H3lZ/2Yu+wwR7JLuGveptO+3i/eWc/H9w13hIqz+eOCPRSV27u7/nRDXy5JCGHxngzu+fcmvtlxgt9d1ZOVB7O4472NdIkKYMHDo6i2GjzwwWYy62xf8OmmY7xx6wCnwPfrz3bw9fYTvPKzftw0OIEfdp0cmLz5aN4FB5UVB7Ic6+dsOppXb8iUc1NQERFp4bw8zHw1cyTFFdV0jgw443U9Y4PoGXv2Qbs3DYpnwY40lh/IcoxVmTG2C0M6huFhMeHraWFszZTm31/Vk8t7RHFJfAg2w2DiayscY1YGtA/hZ4PiGdU1gtkLD7A5JY8jWSVEBXpz0+B4Ptt8jAMZxdz69jr6xQdTWmnl9hEdGNIhDID31ySzITmX313ZkyNZJaw8mI2nxcRbvxhE+3B7cBjTLZIQP0+yiipYczibVxcdAOBQZjH/WH6EimormUUVxIf6csvgBFYezGZDci53z9vIH6/ry63D2nMos5hvdpwAYO6yw4zqGsGmoydXDd58NI/rBrS7kLfFseIw2Pd7UlC5MCajBe9EVVhYSHBwMAUFBQQFnf2HT0REGuZEfhmTXl1BUUU1lySE8OWDIxo0TmPp/kzufG8jAB/cPYxRXSOczpdVWvHyMGMxmziUWcTN/1jnaHEASAz3Y8ljl5FWUM5lryzFZkBMkA9Bvh4cyCjmjhEdeP7a3k6v+bsvd/Lh+hQ6RfpzJKsEswlshj28gX2hu3/+3yAm9o6hstrG777cyaebj2Exm/j0/uF8tD6FT+ts+HhZt0iWH8jCy2Km0mqjV2wQ3z0yukHfN8MwyCqqICrIhyqrjUEvLqKwpqtqcGIonz0wokGv0xacz99vzfoREREncSG+vHJTP7pEBfDM1T0bPJj08u5R/OWm/vxham9Gdgk/7byvl8UxeLhLVCBfPDCCh8d35clJ3Qn18+RoTikLdqbx9soj1G45lF5YzoGMYgK8PXhoXJfTXrO2teNIlr0l566RHRndNYLKahuV1TZGdYngipqp3V4eZl7+WT+u6R+H1Wbw0H+3Mr9mDM7omlC1vGZ9mduGJwKwL73Qab2aMykoreLu9zcx9E9L+MuP+1l3JIfC8mr8vOwrF28/ll/v6sFybur6ERGR00zuE8vkmg0Vz8fPBsU3+NoOEf48dkU3AGw2g78uOsDriw86domeO30gb688wpaUfGaO60J4zQq7dQ1qH+qYgeTtYea+yzpRVmll4qsrsNoMnrm6l1PQMplM/PG6Pmw5muf4Opd2CuMvN/Vn1J9/ospqT0i3j+jA97vSOZ5fxvbUfPy8LLz8w35S80opKK3imkvieO6aXnh7WNhxLJ8Z/91Caq799d5ceojlB4IBmHpJHD/tyySjsIKtKfkM73x6gDub/NJKPt9ynE83pVJZbeO/915KTHDDBiDXxzAMtqXm8+nmY2xOzuN3V/V0rE7srhRURETE5W4b0YF/rjjCkZoxLv3jg5ncJ4YJvaI5klVyxunHZrOJW4YkMHvRAe4Y0cGxrcH8GSOpstrqfV6wryev3nIJP//nWmwGPDC2C9FBPlx3STs+3XyMvu2CSQjzY1BiKMfzy1i6L5Ovt59wGpT73/UpHMospldsEP9em4zNgPZhfvSND2bBjjR2Hrdv7jixdwzFFVa+2X6CDUm55xVUMgrLuepvq8ius1bMb7/cyTu3D76gKdOGYfDkZztqZkHZvb7koNsHFXX9iIiIywX7evJ/Nd0tAPdf1hmTyYSnxXzONVIeHNuZ//1yOL+e3MNxrGdskGO6cX2Gdgzj79MH8eLU3oyp6fZ5YlJ3ru4Xy2+v7AnAoMRQAN5ZnURmUQUdI/z5/IHhzJ0+kABvDzYk5TJvjT2kXNs/jm9mjmL2zf3p084+5iLA24MRncMZ2tE+QHhjcu55fU/mLjtMdrF9MPCTk7rjZTHz075M5m87TkFpFQt2pJFZz3YHh7OKeWv5YVJySp2Of7rpGJ/VjM+5pn8cJpN9sHBty5K7UouKiIi4hbtGdeTzLceIDfZ12vvoXDwsZkcYOB+T+zh/jeggH968daDjcW1QqZ1y8ucb+zEo0f51OkUGcP8Hm7GYTTx3TS/H7tMAb04byMMfb2VKn1i8PSwMrZnJtPloHlVWG541+z4dzCjiREE5ZhPsPlHItztOkJxdyuyb+9M/IYT/bkhxfN2RXexh6pUf9/PbL3ZhNXZSWW0jMtCb9+8cSq+4INIKynjjp0N8sjEVq81g9sID3DWqIz8fkkCl1cZzNSsWPzGxOw+M7UxmYTnrk3JZsOME943p7Kj/y63H+OeKJOKCfegcFcDgxNDzej8am2b9iIiI26istmE24bSJo6tUW230fX4hZVVWbhueyB+m9nE6bxhGg7pgbDaDgX9cRH5pFS9O7c2twxL5y8L9zF12uN7rvSxmhnQMZfWhHIZ0COV/vxyOyWSiymrj+r+vZtdx+7YE/l4WSiqtBHp7MKxTGEv3Z2GtGYXcMcK/3u0NRnQO54O7h2E2m/jPuqM8M38X/eKD+XrmKABKKqoZ+eefyC89ueHkVX1jmTN94GmvdTHO5++3WlRERMRt1E4rdgceFjO/mdKDLSl5Tt1KtRo6TsRsNnFV31g+XJ/CM1/t5s2lh8gotI876RETiMlkIiLAi8l9Yli+P4uFezJYfSgHgEcndHN8HU+LmXduH8LX204wsksE7UJ9ue/fm1iflMvivfY1by7tFMbjE7szODGUn/Zl8refDrE/vZDyKnvry6u3XIK5ZubVlD4xPPfVLnYcK+BoTgmJ4f58tCGF/NIqOoT7cfeojhzOKqFvu+CL/l5eDLWoiIiINLEqq41/rjjC60sOUlltw9fTwp9/1o9r+8c5XVdeZeWueRtZc9i5NeVMyquszF50gGqrwc+HJtAt+vTxPIZhkFlUgb+3BwHezu0Tv/jXelYdyubJSd25e1RHxry8lMyiCl6+sR83D0lonJuvx/n8/VZQERERaSZHsor5Ystxrukfd8ZBwiUV1Xyx9Tjje0QRF+LbpPV8sjGFpz7fiY+nmSEdwlh5MJvYYB+WP3l5k7ZuKaiIiIjIOZVWVnPnextZn3RyRtJz1/TizpEdm/TraoyKiIiInJOflwcf33cpS/dn8velh7GYTfx8SHtXl+VEQUVERKQNM5lMjOsRzbge0a4upV7uM7xaRERE5BQKKiIiIuK2FFRERETEbSmoiIiIiNtSUBERERG3paAiIiIibktBRURERNyWgoqIiIi4LQUVERERcVsKKiIiIuK23CKozJkzhw4dOuDj48OwYcPYsGGDq0sSERERN+DyoPLJJ5/w2GOP8dxzz7Flyxb69+/PpEmTyMzMdHVpIiIi4mIuDyqzZ8/m3nvv5c4776RXr1689dZb+Pn58e6777q6NBEREXExlwaVyspKNm/ezIQJExzHzGYzEyZMYO3ataddX1FRQWFhodOHiIiItF4ervzi2dnZWK1WoqOdt5aOjo5m3759p10/a9YsXnjhhdOOK7CIiIi0HLV/tw3DOOe1Lg0q5+vpp5/mscceczw+fvw4vXr1IiEhwYVViYiIyIUoKioiODj4rNe4NKhERERgsVjIyMhwOp6RkUFMTMxp13t7e+Pt7e14HBAQQGpqKoGBgZhMpkatrbCwkISEBFJTUwkKCmrU13YHrf3+QPfYGrT2+wPdY2vQ2u8PGv8eDcOgqKiIuLi4c17r0qDi5eXFoEGDWLJkCddddx0ANpuNJUuWMHPmzHM+32w2Ex8f36Q1BgUFtdp/eND67w90j61Ba78/0D22Bq39/qBx7/FcLSm1XN7189hjj3H77bczePBghg4dymuvvUZJSQl33nmnq0sTERERF3N5ULnlllvIysri2WefJT09nUsuuYQffvjhtAG2IiIi0va4PKgAzJw5s0FdPc3J29ub5557zmlMTGvS2u8PdI+tQWu/P9A9tgat/f7AtfdoMhoyN0hERETEBVy+Mq2IiIjImSioiIiIiNtSUBERERG3paAiIiIibktBpR5z5syhQ4cO+Pj4MGzYMDZs2ODqki7YrFmzGDJkCIGBgURFRXHdddexf/9+p2vGjh2LyWRy+rj//vtdVPH5ef7550+rvUePHo7z5eXlzJgxg/DwcAICArjxxhtPWwnZ3XXo0OG0ezSZTMyYMQNome/fihUruOaaa4iLi8NkMjF//nyn84Zh8OyzzxIbG4uvry8TJkzg4MGDTtfk5uYyffp0goKCCAkJ4e6776a4uLgZ7+LMznZ/VVVVPPXUU/Tt2xd/f3/i4uK47bbbOHHihNNr1Pe+v/TSS818J2d2rvfwjjvuOK3+yZMnO13jzu8hnPse6/u5NJlMvPLKK45r3Pl9bMjfh4b8Dk1JSeGqq67Cz8+PqKgonnzySaqrqxutTgWVU3zyySc89thjPPfcc2zZsoX+/fszadIkMjMzXV3aBVm+fDkzZsxg3bp1LFq0iKqqKiZOnEhJSYnTdffeey9paWmOj5dfftlFFZ+/3r17O9W+atUqx7lf/epXfPPNN3z66acsX76cEydOcMMNN7iw2vO3ceNGp/tbtGgRADfddJPjmpb2/pWUlNC/f3/mzJlT7/mXX36Zv/3tb7z11lusX78ef39/Jk2aRHl5ueOa6dOns3v3bhYtWsS3337LihUruO+++5rrFs7qbPdXWlrKli1beOaZZ9iyZQtffPEF+/fv59prrz3t2j/84Q9O7+tDDz3UHOU3yLneQ4DJkyc71f/RRx85nXfn9xDOfY917y0tLY13330Xk8nEjTfe6HSdu76PDfn7cK7foVarlauuuorKykrWrFnD+++/z7x583j22Wcbr1BDnAwdOtSYMWOG47HVajXi4uKMWbNmubCqxpOZmWkAxvLlyx3HLrvsMuORRx5xXVEX4bnnnjP69+9f77n8/HzD09PT+PTTTx3H9u7dawDG2rVrm6nCxvfII48YnTt3Nmw2m2EYLfv9MwzDAIwvv/zS8dhmsxkxMTHGK6+84jiWn59veHt7Gx999JFhGIaxZ88eAzA2btzouOb77783TCaTcfz48WarvSFOvb/6bNiwwQCMo0ePOo4lJiYar776atMW10jqu8fbb7/dmDp16hmf05LeQ8No2Ps4depUY9y4cU7HWtL7eOrfh4b8Dv3uu+8Ms9lspKenO66ZO3euERQUZFRUVDRKXWpRqaOyspLNmzczYcIExzGz2cyECRNYu3atCytrPAUFBQCEhYU5Hf/www+JiIigT58+PP3005SWlrqivAty8OBB4uLi6NSpE9OnTyclJQWAzZs3U1VV5fR+9ujRg/bt27fY97OyspIPPviAu+66y2kjzpb8/p0qKSmJ9PR0p/ctODiYYcOGOd63tWvXEhISwuDBgx3XTJgwAbPZzPr165u95otVUFCAyWQiJCTE6fhLL71EeHg4AwYM4JVXXmnU5vTmsGzZMqKioujevTsPPPAAOTk5jnOt7T3MyMhgwYIF3H333aedaynv46l/HxryO3Tt2rX07dvXaTX5SZMmUVhYyO7duxulLrdYmdZdZGdnY7VaT1u+Pzo6mn379rmoqsZjs9l49NFHGTlyJH369HEcv/XWW0lMTCQuLo4dO3bw1FNPsX//fr744gsXVtsww4YNY968eXTv3p20tDReeOEFRo8eza5du0hPT8fLy+u0X/7R0dGkp6e7puCLNH/+fPLz87njjjscx1ry+1ef2vemvp/D2nPp6elERUU5nffw8CAsLKzFvbfl5eU89dRTTJs2zWmzt4cffpiBAwcSFhbGmjVrePrpp0lLS2P27NkurLbhJk+ezA033EDHjh05fPgwv/3tb5kyZQpr167FYrG0qvcQ4P333ycwMPC0ruWW8j7W9/ehIb9D09PT6/1ZrT3XGBRU2pAZM2awa9cupzEcgFOfcN++fYmNjWX8+PEcPnyYzp07N3eZ52XKlCmOz/v168ewYcNITEzkf//7H76+vi6srGm88847TJkyxWlr9Jb8/rV1VVVV3HzzzRiGwdy5c53OPfbYY47P+/Xrh5eXF7/85S+ZNWtWi1iq/ec//7nj8759+9KvXz86d+7MsmXLGD9+vAsraxrvvvsu06dPx8fHx+l4S3kfz/T3wR2o66eOiIgILBbLaSOaMzIyiImJcVFVjWPmzJl8++23LF26lPj4+LNeO2zYMAAOHTrUHKU1qpCQELp168ahQ4eIiYmhsrKS/Px8p2ta6vt59OhRFi9ezD333HPW61ry+wc43puz/RzGxMScNsC9urqa3NzcFvPe1oaUo0ePsmjRIqfWlPoMGzaM6upqkpOTm6fARtapUyciIiIc/y5bw3tYa+XKlezfv/+cP5vgnu/jmf4+NOR3aExMTL0/q7XnGoOCSh1eXl4MGjSIJUuWOI7ZbDaWLFnC8OHDXVjZhTMMg5kzZ/Lll1/y008/0bFjx3M+Z9u2bQDExsY2cXWNr7i4mMOHDxMbG8ugQYPw9PR0ej/3799PSkpKi3w/33vvPaKiorjqqqvOel1Lfv8AOnbsSExMjNP7VlhYyPr16x3v2/Dhw8nPz2fz5s2Oa3766SdsNpsjqLmz2pBy8OBBFi9eTHh4+Dmfs23bNsxm82ndJS3FsWPHyMnJcfy7bOnvYV3vvPMOgwYNon///ue81p3ex3P9fWjI79Dhw4ezc+dOp9BZG7x79erVaIVKHR9//LHh7e1tzJs3z9izZ49x3333GSEhIU4jmluSBx54wAgODjaWLVtmpKWlOT5KS0sNwzCMQ4cOGX/4wx+MTZs2GUlJScZXX31ldOrUyRgzZoyLK2+Yxx9/3Fi2bJmRlJRkrF692pgwYYIRERFhZGZmGoZhGPfff7/Rvn1746effjI2bdpkDB8+3Bg+fLiLqz5/VqvVaN++vfHUU085HW+p719RUZGxdetWY+vWrQZgzJ4929i6datj1stLL71khISEGF999ZWxY8cOY+rUqUbHjh2NsrIyx2tMnjzZGDBggLF+/Xpj1apVRteuXY1p06a56pacnO3+KisrjWuvvdaIj483tm3b5vRzWTtLYs2aNcarr75qbNu2zTh8+LDxwQcfGJGRkcZtt93m4js76Wz3WFRUZDzxxBPG2rVrjaSkJGPx4sXGwIEDja5duxrl5eWO13Dn99Awzv3v1DAMo6CgwPDz8zPmzp172vPd/X08198Hwzj379Dq6mqjT58+xsSJE41t27YZP/zwgxEZGWk8/fTTjVangko93njjDaN9+/aGl5eXMXToUGPdunWuLumCAfV+vPfee4ZhGEZKSooxZswYIywszPD29ja6dOliPPnkk0ZBQYFrC2+gW265xYiNjTW8vLyMdu3aGbfccotx6NAhx/mysjLjwQcfNEJDQw0/Pz/j+uuvN9LS0lxY8YX58ccfDcDYv3+/0/GW+v4tXbq03n+Xt99+u2EY9inKzzzzjBEdHW14e3sb48ePP+3ec3JyjGnTphkBAQFGUFCQceeddxpFRUUuuJvTne3+kpKSzvhzuXTpUsMwDGPz5s3GsGHDjODgYMPHx8fo2bOn8ac//cnpj7yrne0eS0tLjYkTJxqRkZGGp6enkZiYaNx7772n/Q+fO7+HhnHuf6eGYRj/+Mc/DF9fXyM/P/+057v7+3iuvw+G0bDfocnJycaUKVMMX19fIyIiwnj88ceNqqqqRqvTVFOsiIiIiNvRGBURERFxWwoqIiIi4rYUVERERMRtKaiIiIiI21JQEREREbeloCIiIiJuS0FFRERE3JaCioiIiLgtBRURaZAOHTrw2muvNfj6ZcuWYTKZTtvQrLU63++PiDSMh6sLEJGmMXbsWC655JJG++O5ceNG/P39G3z9iBEjSEtLIzg4uFG+voi0TQoqIm2YYRhYrVY8PM79qyAyMvK8XtvLy6vRtnkXkbZLXT8irdAdd9zB8uXLef311zGZTJhMJpKTkx3dMd9//z2DBg3C29ubVatWcfjwYaZOnUp0dDQBAQEMGTKExYsXO73mqV0bJpOJf/3rX1x//fX4+fnRtWtXvv76a8f5U7t+5s2bR0hICD/++CM9e/YkICCAyZMnk5aW5nhOdXU1Dz/8MCEhIYSHh/PUU09x++23c9111531fletWsXo0aPx9fUlISGBhx9+mJKSEqfaX3zxRaZNm4a/vz/t2rVjzpw5Tq+RkpLC1KlTCQgIICgoiJtvvpmMjAyna7755huGDBmCj48PERERXH/99U7nS0tLueuuuwgMDKR9+/b885//PGvdInJuCioirdDrr7/O8OHDuffee0lLSyMtLY2EhATH+d/85je89NJL7N27l379+lFcXMyVV17JkiVL2Lp1K5MnT+aaa64hJSXlrF/nhRde4Oabb2bHjh1ceeWVTJ8+ndzc3DNeX1payl/+8hf+85//sGLFClJSUnjiiScc5//85z/z4Ycf8t5777F69WoKCwuZP3/+WWs4fPgwkydP5sYbb2THjh188sknrFq1ipkzZzpd98orr9C/f3+2bt3Kb37zGx555BEWLVoEgM1mY+rUqeTm5rJ8+XIWLVrEkSNHuOWWWxzPX7BgAddffz1XXnklW7duZcmSJQwdOtTpa/z1r39l8ODBbN26lQcffJAHHniA/fv3n7V+ETmHRtuHWUTcymWXXWY88sgjTsdqt62fP3/+OZ/fu3dv44033nA8TkxMNF599VXHY8D4/e9/73hcXFxsAMb333/v9LXy8vIMwzCM9957zwCMQ4cOOZ4zZ84cIzo62vE4OjraeOWVVxyPq6urjfbt2xtTp049Y5133323cd999zkdW7lypWE2m42ysjJH7ZMnT3a65pZbbjGmTJliGIZhLFy40LBYLEZKSorj/O7duw3A2LBhg2EYhjF8+HBj+vTpZ6wjMTHR+MUvfuF4bLPZjKioKGPu3LlnfI6InJtaVETaoMGDBzs9Li4u5oknnqBnz56EhIQQEBDA3r17z9mi0q9fP8fn/v7+BAUFkZmZecbr/fz86Ny5s+NxbGys4/qCggIyMjKcWiksFguDBg06aw3bt29n3rx5BAQEOD4mTZqEzWYjKSnJcd3w4cOdnjd8+HD27t0LwN69e0lISHBqderVqxchISGOa7Zt28b48ePPWkvd74fJZCImJuas3w8ROTcNphVpg06dvfPEE0+waNEi/vKXv9ClSxd8fX352c9+RmVl5Vlfx9PT0+mxyWTCZrOd1/WGYZxn9c6Ki4v55S9/ycMPP3zaufbt21/Ua9fl6+t7zmvO9/shIuemFhWRVsrLywur1dqga1evXs0dd9zB9ddfT9++fYmJiSE5OblpCzxFcHAw0dHRbNy40XHMarWyZcuWsz5v4MCB7Nmzhy5dupz24eXl5bhu3bp1Ts9bt24dPXv2BKBnz56kpqaSmprqOL9nzx7y8/Pp1asXYG8tWbJkyUXfp4icH7WoiLRSHTp0YP369SQnJxMQEEBYWNgZr+3atStffPEF11xzDSaTiWeeecYlLQEPPfQQs2bNokuXLvTo0YM33niDvLw8TCbTGZ/z1FNPcemllzJz5kzuuece/P392bNnD4sWLeLNN990XLd69WpefvllrrvuOhYtWsSnn37KggULAJgwYQJ9+/Zl+vTpvPbaa1RXV/Pggw9y2WWXObrJnnvuOcaPH0/nzp35+c9/TnV1Nd999x1PPfVU035TRNo4taiItFJPPPEEFouFXr16ERkZedbxJrNnzyY0NJQRI0ZwzTXXMGnSJAYOHNiM1do99dRTTJs2jdtuu43hw4c7xpv4+Pic8Tn9+vVj+fLlHDhwgNGjRzNgwACeffZZ4uLinK57/PHH2bRpEwMGDOCPf/wjs2fPZtKkSYC9i+arr74iNDSUMWPGMGHCBDp16sQnn3zieP7YsWP59NNP+frrr7nkkksYN24cGzZsaJpvhIg4mIyL7SAWEWkiNpuNnj17cvPNN/Piiy9e8Ot06NCBRx99lEcffbTxihORZqGuHxFxG0ePHmXhwoVcdtllVFRU8Oabb5KUlMStt97q6tJExEXU9SMibsNsNjNv3jyGDBnCyJEj2blzJ4sXL3YMehWRtkddPyIiIuK21KIiIiIibktBRURERNyWgoqIiIi4LQUVERERcVsKKiIiIuK2FFRERETEbSmoiIiIiNtSUBERERG39f8B0v/mt3EBZ74AAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 多层循环神经网络\n",
    "class DeepRNN(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size, num_layers, dropout=0.):\n",
    "        super(DeepRNN, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        self.num_layers = num_layers\n",
    "        self._flat_weight_names = []\n",
    "        self._all_weights = []\n",
    "        self.drop = nn.Dropout(p=dropout)\n",
    "        # 定义每一层循环神经网络的参数，由于参数数量不固定，\n",
    "        # 因此使用统一的命名方法更方便调用和管理\n",
    "        for layer in range(num_layers):\n",
    "            W_xh = nn.Parameter(normal((input_size, hidden_size)))\n",
    "            W_hh = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "            b_h = nn.Parameter(torch.zeros(hidden_size))\n",
    "            layer_params = (W_xh, W_hh, b_h)\n",
    "            params_names = [f'W_xh_l{layer}', f'W_hh_l{layer}', \\\n",
    "                f'b_h_l{layer}']\n",
    "            \n",
    "            # 将新的参数加入到成员列表中\n",
    "            for name, param in zip(params_names, layer_params):\n",
    "                setattr(self, name, param)\n",
    "            self._flat_weight_names.extend(params_names)\n",
    "            self._all_weights.append(params_names)\n",
    "            input_size = hidden_size\n",
    "        self._flat_weights = [getattr(self, wn) if hasattr(self, wn) \\\n",
    "            else None for wn in self._flat_weight_names]\n",
    "    \n",
    "    def __setattr__(self, attr, value):\n",
    "        if hasattr(self, '_flat_weight_names') and \\\n",
    "            attr in self._flat_weight_names:\n",
    "            idx = self._flat_weight_names.index(attr)\n",
    "            self._flat_weights[idx] = value\n",
    "        super().__setattr__(attr, value)\n",
    "    \n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((self.num_layers, batch_size, hidden_size), \n",
    "            dtype=torch.float),)\n",
    "    \n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        layer_hidden_states, = states\n",
    "        layer_h_t = []\n",
    "        input_states = inputs\n",
    "        # 需要保存每一层的输出作为下一层的输入\n",
    "        for layer in range(self.num_layers):\n",
    "            hiddens = []\n",
    "            hidden_state = layer_hidden_states[layer]\n",
    "            for step in range(seq_len):\n",
    "                xh = torch.mm(input_states[step], \n",
    "                    getattr(self, f'W_xh_l{layer}'))\n",
    "                hh = torch.mm(hidden_state, getattr(self, f'W_hh_l{layer}'))\n",
    "                hidden_state = xh + hh + getattr(self, f'b_h_l{layer}')\n",
    "                hidden_state = self.drop(torch.tanh(hidden_state))\n",
    "                hiddens.append(hidden_state)\n",
    "            input_states = torch.stack(hiddens, dim=0)\n",
    "            layer_h_t.append(hidden_state)\n",
    "        return input_states, torch.stack(layer_h_t, dim=0)\n",
    "\n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, dtype=torch.long), \n",
    "    batch_size=16, shuffle=True)\n",
    "deep_rnn = DeepRNN(128, 128, 2)\n",
    "train_rnn_lm(data_loader, deep_rnn, vocab_size, hidden_size=128, \n",
    "    epochs=200, learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f0f1be39",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "需要注意的是，双向循环神经网络在每个位置的输出同时包含了来自左边和右边的信息，也就是整个输入序列的信息。所以双向循环神经网络并不能用于语言模型，因为语言模型需要仅根据序列中每个词左边的信息来预测这个词。\n",
    "\n",
    "下面的双向循环神经网络是一个简单的示例，要求一次只能输入一个序列。如果想在一个批次中并行处理不同长度的输入序列以获得更高的运行效率，可以通过填充将不同长度的输入对齐。单向循环神经网络的填充较为简单，只需在每个序列末尾添加字符就可以。但是双向循环神经网络的填充更加复杂，正向和反向循环神经网络的读取顺序相反，难以保证两个方向的循环神经网络都填充在末尾，实现起来较为困难。\n",
    "解决方案参考PyTorch中的pack_padded_sequence和pad_packed_sequence。双向循环神经网络不能用于训练语言模型，因此不再提供训练示例代码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "0344d588",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 双向循环神经网络\n",
    "class BiRNN(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size):\n",
    "        super(BiRNN, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        # 正向循环神经网络参数\n",
    "        self.W_xh = nn.Parameter(normal((input_size, hidden_size)))\n",
    "        self.W_hh = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_h = nn.Parameter(torch.zeros(hidden_size))\n",
    "        # 反向循环神经网络参数\n",
    "        self.W_xh_reverse = nn.Parameter(normal((input_size, hidden_size)))\n",
    "        self.W_hh_reverse = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_h_reverse = nn.Parameter(torch.zeros(hidden_size))\n",
    "        \n",
    "    # 分别为正向和反向循环神经网络准备初始状态\n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((batch_size, hidden_size), dtype=torch.float),\n",
    "               torch.zeros((batch_size, hidden_size), dtype=torch.float))\n",
    "    \n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        hidden_state, reverse_hidden_state = states\n",
    "        hiddens = []\n",
    "        for step in range(seq_len):\n",
    "            xh = torch.mm(inputs[step], self.W_xh)\n",
    "            hh = torch.mm(hidden_state, self.W_hh)\n",
    "            hidden_state = xh + hh + self.b_h\n",
    "            hidden_state = torch.tanh(hidden_state)\n",
    "            hiddens.append(hidden_state)\n",
    "        reverse_hiddens = []\n",
    "        for step in range(seq_len-1, -1, -1):\n",
    "            xh = torch.mm(inputs[step], self.W_xh_reverse)\n",
    "            hh = torch.mm(reverse_hidden_state, self.W_hh_reverse)\n",
    "            reverse_hidden_state = xh + hh + self.b_h_reverse\n",
    "            reverse_hidden_state = torch.tanh(reverse_hidden_state)\n",
    "            reverse_hiddens.insert(0, reverse_hidden_state)\n",
    "        # 将正向和反向循环神经网络输出的隐状态拼接在一起\n",
    "        combined_hiddens = []\n",
    "        for h1, h2 in zip(hiddens, reverse_hiddens):\n",
    "            combined_hiddens.append(torch.cat([h1, h2], dim=-1))\n",
    "        return torch.stack(combined_hiddens, dim=0), ()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b79ef2c6",
   "metadata": {},
   "source": [
    "下面实现一个带有缩放点乘注意力的循环神经网络，并用其训练语言模型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "b5c32275",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=0.9792: 100%|█| 200/200 [11:24<00:00,  3.42s\n"
     ]
    },
    {
     "data": {
      "image/png": "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Ree6en02mw3Lly/H+PHjERQUhLi4ONx5550oKipye46O3vcXX3yxn19J57p7D+++++52458/f77bNb78HgLdv8aO/rsUBAEvv/yyeo0vv489+Xzoyd+heXl5uOGGGxAYGIioqCg8/fTTsNvtHhsng0obH330EZ544gk8//zzOHjwIDIyMnDdddehrKzM20PrlS1btmDZsmXYvXs31q9fD5vNhmuvvRb19fVu191///0oLi5Wv1566SUvjfjijRs3zm3s27dvV+/72c9+hi+++AJr1qzBli1bUFRUhFtuucWLo714+/btc3t969evBwB8//vfV68ZaO9ffX09MjIysHLlyg7vf+mll/DGG2/gL3/5C/bs2YOgoCBcd911aGpqUq9ZunQpTpw4gfXr1+PLL7/E1q1b8cADD/TXS+hSV6+voaEBBw8exLPPPouDBw/ik08+QVZWFm666aZ21/7mN79xe19/+tOf9sfwe6S79xAA5s+f7zb+Dz74wO1+X34Pge5fo+trKy4uxjvvvANBEHDrrbe6Xeer72NPPh+6+zvU4XDghhtuQEtLC3bu3In33nsPq1evxnPPPee5gYrkZvr06eKyZcvU7x0OhxgXFyeuWLHCi6PynLKyMhGAuGXLFvW22bNni4899pj3BnUJnn/+eTEjI6PD+2pqakQ/Pz9xzZo16m2nTp0SAYi7du3qpxF63mOPPSampqaKTqdTFMWB/f6JoigCED/99FP1e6fTKcbExIgvv/yyeltNTY2o1+vFDz74QBRFUTx58qQIQNy3b596zVdffSUKgiAWFhb229h7ou3r68jevXtFAOKFCxfU25KTk8VXX321bwfnIR29xrvuuktctGhRp48ZSO+hKPbsfVy0aJF49dVXu902kN7Htp8PPfk79L///a+o0WjEkpIS9ZpVq1aJRqNRbG5u9si4WFFx0dLSggMHDmDevHnqbRqNBvPmzcOuXbu8ODLPsVgsAICwsDC32//1r38hIiIC6enpeOaZZ9DQ0OCN4fXK2bNnERcXh+HDh2Pp0qXIy8sDABw4cAA2m83t/Rw9ejSSkpIG7PvZ0tKCf/7zn/jxj3/sdhDnQH7/2srJyUFJSYnb+2YymTBjxgz1fdu1axfMZjOmTp2qXjNv3jxoNBrs2bOn38d8qSwWCwRBgNlsdrv9xRdfRHh4OCZNmoSXX37Z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RI99eO7btw9BQUE9vv7yyy9HcXExTCaTR34+EQ1NDCpEQ5goinA4HNDpuv+rIDIy8qKe29/f32PHvBPR0MWpH6JB6O6778aWLVvw+uuvQxAECIKA3NxcdTrmq6++wpQpU6DX67F9+3acO3cOixYtQnR0NIKDgzFt2jRs2LDB7TnbTm0IgoC///3vWLx4MQIDAzFixAh8/vnn6v1tp35Wr14Ns9mMb775BmPGjEFwcDDmz5+P4uJi9TF2ux2PPvoozGYzwsPDsXz5ctx11124+eabu3y927dvx5VXXomAgAAkJibi0UcfRX19vdvYf/vb32LJkiUICgpCfHw8Vq5c6fYceXl5WLRoEYKDg2E0GnHbbbehtLTU7ZovvvgC06ZNg8FgQEREBBYvXux2f0NDA3784x8jJCQESUlJ+Otf/9rluImoewwqRIPQ66+/jszMTNx///0oLi5GcXExEhMT1ft/8Ytf4MUXX8SpU6cwYcIE1NXV4frrr8fGjRtx6NAhzJ8/HwsXLkReXl6XP+fXv/41brvtNhw9ehTXX389li5diqqqqk6vb2howB//+Ef84x//wNatW5GXl4ennnpKvf9//ud/8K9//QvvvvsuduzYAavVis8++6zLMZw7dw7z58/HrbfeiqNHj+Kjjz7C9u3b8cgjj7hd9/LLLyMjIwOHDh3CL37xCzz22GNYv349AMDpdGLRokWoqqrCli1bsH79epw/fx633367+vh169Zh8eLFuP7663Ho0CFs3LgR06dPd/sZ//u//4upU6fi0KFDePjhh/HQQw8hKyury/ETUTc8dg4zEfmU2bNni4899pjbbcqx9Z999lm3jx83bpz4pz/9Sf0+OTlZfPXVV9XvAYi/+tWv1O/r6upEAOJXX33l9rOqq6tFURTFd999VwQgZmdnq49ZuXKlGB0drX4fHR0tvvzyy+r3drtdTEpKEhctWtTpOO+9917xgQcecLtt27ZtokajERsbG9Wxz58/3+2a22+/XVywYIEoiqL47bffilqtVszLy1PvP3HihAhA3Lt3ryiKopiZmSkuXbq003EkJyeLP/zhD9XvnU6nGBUVJa5atarTxxBR91hRIRqCpk6d6vZ9XV0dnnrqKYwZMwZmsxnBwcE4depUtxWVCRMmqH8OCgqC0WhEWVlZp9cHBgYiNTVV/T42Nla93mKxoLS01K1KodVqMWXKlC7HcOTIEaxevRrBwcHq13XXXQen04mcnBz1uszMTLfHZWZm4tSpUwCAU6dOITEx0a3qNHbsWJjNZvWaw4cPY+7cuV2OxfX3IQgCYmJiuvx9EFH32ExLNAS1Xb3z1FNPYf369fjjH/+ItLQ0BAQE4Hvf+x5aWlq6fB4/Pz+37wVBgNPpvKjrRVG8yNG7q6urw09+8hM8+uij7e5LSkq6pOd2FRAQ0O01F/v7IKLusaJCNEj5+/vD4XD06NodO3bg7rvvxuLFizF+/HjExMQgNze3bwfYhslkQnR0NPbt26fe5nA4cPDgwS4fN3nyZJw8eRJpaWntvvz9/dXrdu/e7fa43bt3Y8yYMQCAMWPGID8/H/n5+er9J0+eRE1NDcaOHQtAqpZs3Ljxkl8nEV0cVlSIBqmUlBTs2bMHubm5CA4ORlhYWKfXjhgxAp988gkWLlwIQRDw7LPPeqUS8NOf/hQrVqxAWloaRo8ejT/96U+orq6GIAidPmb58uW47LLL8Mgjj+C+++5DUFAQTp48ifXr1+PNN99Ur9uxYwdeeukl3HzzzVi/fj3WrFmDdevWAQDmzZuH8ePHY+nSpXjttddgt9vx8MMPY/bs2eo02fPPP4+5c+ciNTUVP/jBD2C32/Hf//4Xy5cv79tfCtEQx4oK0SD11FNPQavVYuzYsYiMjOyy3+SVV15BaGgoLr/8cixcuBDXXXcdJk+e3I+jlSxfvhxLlizBnXfeiczMTLXfxGAwdPqYCRMmYMuWLThz5gyuvPJKTJo0Cc899xzi4uLcrnvyySexf/9+TJo0Cb/73e/wyiuv4LrrrgMgTdGsXbsWoaGhmDVrFubNm4fhw4fjo48+Uh8/Z84crFmzBp9//jkmTpyIq6++Gnv37u2bXwQRqQTxUieIiYj6iNPpxJgxY3Dbbbfht7/9ba+fJyUlBY8//jgef/xxzw2OiPoFp36IyGdcuHAB3377LWbPno3m5ma8+eabyMnJwR133OHtoRGRl3Dqh4h8hkajwerVqzFt2jTMnDkTx44dw4YNG9SmVyIaejj1Q0RERD6LFRUiIiLyWQwqRERE5LMYVIiIiMhnMagQERGRz2JQISIiIp/FoEJEREQ+i0GFiIiIfBaDChEREfms/w/yVmIkgWZp7gAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "class AttentionRNN(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size):\n",
    "        super(AttentionRNN, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        # 循环神经网络参数\n",
    "        self.W_xh = nn.Parameter(normal((input_size, hidden_size)))\n",
    "        self.W_hh = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_h = nn.Parameter(torch.zeros(hidden_size))\n",
    "    \n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((batch_size, hidden_size),\\\n",
    "            dtype=torch.float),)\n",
    "    \n",
    "    # 缩放点乘注意力\n",
    "    def attention(self, query, keys, values):\n",
    "        \"\"\"\n",
    "        query: batch_size * hidden_size\n",
    "        keys/values: batch_size * prev_len * hidden_size\n",
    "        \"\"\"\n",
    "        # batch_size * 1 * hidden_size\n",
    "        query = torch.unsqueeze(query, 1)\n",
    "        # batch_size * hidden_size * prev_len\n",
    "        keys = torch.permute(keys, (0, 2, 1))\n",
    "        # batch_size * 1 * prev_len\n",
    "        attention_scores = torch.bmm(query, keys) / np.sqrt(\\\n",
    "            self.hidden_size)\n",
    "        # batch_size * 1 * prev_len\n",
    "        attention_weights = F.softmax(attention_scores, dim=1)\n",
    "        # batch_size * hidden_size\n",
    "        attention_state = torch.squeeze(torch.bmm(attention_weights,\\\n",
    "            values))\n",
    "        return attention_state\n",
    "\n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        hidden_state, = states\n",
    "        hiddens = []\n",
    "        attention_hiddens = []\n",
    "        for step in range(seq_len):\n",
    "            xh = torch.mm(inputs[step], self.W_xh)\n",
    "            hh = torch.mm(hidden_state, self.W_hh)\n",
    "            hidden_state = xh + hh + self.b_h\n",
    "            hidden_state = torch.tanh(hidden_state)\n",
    "            \n",
    "            if step > 0:\n",
    "                # batch_size * hidden_size\n",
    "                query = hidden_state\n",
    "                # batch_size * prev_len * hidden_size\n",
    "                keys = values = torch.permute(torch.stack(hiddens,\\\n",
    "                    dim=0), (1, 0, 2))\n",
    "                \n",
    "                attention_state = self.attention(query, keys, values)                \n",
    "                attention_hiddens.append(attention_state)\n",
    "            else:\n",
    "                # 第0步，历史隐状态为空，无法进行注意力运算，\n",
    "                # 直接用隐状态填充\n",
    "                attention_hiddens.append(hidden_state)\n",
    "                \n",
    "            hiddens.append(hidden_state)\n",
    "        return torch.stack(attention_hiddens, dim=0), \\\n",
    "            (attention_state,)\n",
    "    \n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, dtype=torch.long), \n",
    "    batch_size=16, shuffle=True)\n",
    "\n",
    "attention_rnn = AttentionRNN(128, 128)\n",
    "train_rnn_lm(data_loader, attention_rnn, vocab_size, hidden_size=128, \n",
    "    epochs=200, learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c95d2f4b",
   "metadata": {},
   "source": [
    "下面是多头注意力的代码实现。我们在实现AttentionRNN时将注意力计算封装在成员函数里面，因此实现多头注意力时可以直接继承AttentionRNN类，只用改写构造函数和attention()成员方法即可。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "6373e7ab",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=1.4769: 100%|█| 200/200 [28:21<00:00,  8.51s\n"
     ]
    },
    {
     "data": {
      "image/png": "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DocDH330UZdjOHPmDJYsWYLrrrsOhw4dwjvvvINt27bh3nvvDbjumWeewbRp03DgwAE88sgjuP/++7F+/XoAgM/nw7Jly1BTU4MtW7Zg/fr1OHv2LG644Qb1+WvXrsU111yDyy67DAcOHMDGjRtxzjnnBPyMP/7xj5g9ezYOHDiAe+65B3fffTdOnjzZ5fiJqBv9drwhEYWUCy+8ULz//vsD7lNOg/3oo4+6ff6kSZPEF198Ub2dkZEhPvfcc+ptAOL/+3//T73d0NAgAhDXrVsX8LNqa2tFURTF119/XQQQcLr1yy+/LCYkJKi3ExISxGeeeUa97fF4xPT0dHHZsmWdjvP2228X77zzzoD7vv76a1Gj0YhNTU3q2JcsWRJwzQ033CAuXbpUFEVR/PLLL0WtVisWFBSojx89elQEIO7evVsURVGcN2+euHz58k7HkZGRId58883qbZ/PJ8bHx4urV6/u9DlE1D1WVIhGoNmzZwfcbmhowMMPP4wJEybAZrMhMjISx48f77aiMnXqVPX7iIgIWCwWVFRUdHq9yWRCZmamejspKUm93m63o7y8PKBKodVqMWvWrC7H8O2332LNmjWIjIxUvy699FL4fD7k5uaq182bNy/gefPmzcPx48cBAMePH0daWlpA1WnixImw2WzqNQcPHsTChQu7HIv/n4cgCEhMTOzyz4OIusdmWqIRqO3qnYcffhjr16/HH/7wB2RlZSE8PBzf//734Xa7u3ydsLCwgNuCIMDn8/XqelEUezn6QA0NDfjpT3+K++67r91j6enp3+m1/YWHh3d7TW//PIioe6yoEA1Ter0eXq+3R9d+8803uO2223DNNddgypQpSExMRF5e3sAOsA2r1YqEhATs2bNHvc/r9WL//v1dPm/mzJk4duwYsrKy2n3p9Xr1up07dwY8b+fOnZgwYQIAYMKECSgsLERhYaH6+LFjx1BXV4eJEycCkKolGzdu/M7vk4h6hxUVomFq1KhR2LVrF/Ly8hAZGYno6OhOrx07diw++OADXHnllRAEAb/61a+CUgn42c9+hlWrViErKwvZ2dl48cUXUVtbC0EQOn3OypUrce655+Lee+/FT37yE0RERODYsWNYv349XnrpJfW6b775Br///e9x9dVXY/369Xjvvfewdu1aAMCiRYswZcoULF++HM8//zw8Hg/uueceXHjhheo02WOPPYaFCxciMzMTP/zhD+HxePCf//wHK1euHNg/FKIRjhUVomHq4YcfhlarxcSJExEXF9dlv8mzzz6LqKgonHfeebjyyitx6aWXYubMmYM4WsnKlStx44034pZbbsG8efPUfhOj0djpc6ZOnYotW7bg1KlTOP/88zFjxgz8+te/RnJycsB1Dz30EPbu3YsZM2bgt7/9LZ599llceumlAKQpmo8//hhRUVG44IILsGjRIowZMwbvvPOO+vwFCxbgvffewyeffILp06fj4osvxu7duwfmD4KIVIL4XSeIiYgGiM/nw4QJE3D99dfjySef7PPrjBo1Cg888AAeeOCB/hscEQ0KTv0QUcjIz8/Hl19+iQsvvBAulwsvvfQScnNzcdNNNwV7aEQUJJz6IaKQodFosGbNGsyZMwfz58/H4cOHsWHDBrXplYhGHk79EBERUchiRYWIiIhCFoMKERERhSwGFSIiIgpZDCpEREQUshhUiIiIKGQxqBAREVHIYlAhIiKikMWgQkRERCGLQYWIiIhC1v8HgidxNrRwj8sAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 多头注意力循环神经网络\n",
    "class MultiHeadAttentionRNN(AttentionRNN):\n",
    "    def __init__(self, input_size, hidden_size, num_heads=4):\n",
    "        super().__init__(input_size, hidden_size)\n",
    "        # 简单起见，一般要求hidden_size能够被num_heads整除\n",
    "        assert hidden_size % num_heads == 0\n",
    "        self.num_heads = num_heads\n",
    "        # 多头注意力参数，用于将查询、键、值映射到子空间\n",
    "        self.W_aq = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_aq = nn.Parameter(torch.zeros(hidden_size))\n",
    "        self.W_ak = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_ak = nn.Parameter(torch.zeros(hidden_size))\n",
    "        self.W_av = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_av = nn.Parameter(torch.zeros(hidden_size))\n",
    "        self.W_ac = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_ac = nn.Parameter(torch.zeros(hidden_size))\n",
    "\n",
    "    # 多头缩放点乘注意力\n",
    "    def attention(self, query, keys, values):\n",
    "        \"\"\"\n",
    "        query: batch_size * hidden_size\n",
    "        keys/values: batch_size * prev_len * hidden_size\n",
    "        \"\"\"\n",
    "        query = torch.mm(query, self.W_aq) + self.b_aq\n",
    "        ori_shape = keys.size()\n",
    "        \n",
    "        keys = torch.reshape(torch.mm(torch.flatten(keys, \n",
    "                start_dim=0, end_dim=1), self.W_ak) + \n",
    "                self.b_ak, ori_shape)\n",
    "        values = torch.reshape(torch.mm(torch.flatten(values, \n",
    "                start_dim=0, end_dim=1), self.W_av) + \n",
    "                self.b_av, ori_shape)\n",
    "        # batch_size * 1 * hidden_size\n",
    "        query = torch.unsqueeze(query, 1)\n",
    "        # batch_size * hidden_size * prev_len\n",
    "        keys = torch.permute(keys, (0, 2, 1))\n",
    "        \n",
    "        head_size = self.hidden_size // self.num_heads\n",
    "        query = torch.split(query, head_size, 2)\n",
    "        keys = torch.split(keys, head_size, 1)\n",
    "        values = torch.split(values, head_size, 2)\n",
    "        \n",
    "        heads = []\n",
    "        for i in range(self.num_heads):\n",
    "            # batch_size * 1 * prev_len\n",
    "            head_scores = torch.bmm(query[i], keys[i]) / np.sqrt(\n",
    "                self.hidden_size // self.num_heads) \n",
    "            # batch_size * 1 * prev_len\n",
    "            head_weights = F.softmax(head_scores, dim=1)\n",
    "            # batch_size * head_size\n",
    "            head_state = torch.squeeze(torch.bmm(head_weights, \n",
    "                values[i])) \n",
    "            heads.append(head_state)\n",
    "        heads = torch.cat(heads, dim=1)        \n",
    "        attention_state = torch.mm(heads, self.W_ac) + self.b_ac\n",
    "\n",
    "        return attention_state\n",
    "\n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, \n",
    "    dtype=torch.long), batch_size=16, shuffle=True)\n",
    "\n",
    "mha_rnn = MultiHeadAttentionRNN(128, 128)\n",
    "train_rnn_lm(data_loader, mha_rnn, vocab_size, hidden_size=128, \n",
    "    epochs=200, learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "166d4dce",
   "metadata": {},
   "source": [
    "下面来实现Transformer模型，包括加入了位置编码的嵌入层、缩放点乘注意力、多头注意力、层归一化等具体实现。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "0e4110a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "代码修改自GitHub项目huggingface/transformers\n",
    "（Copyright (c) 2020, The HuggingFace Team, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 实现Transformer模型\n",
    "class EmbeddingLayer(nn.Module):\n",
    "    def __init__(self, vocab_size, max_len, embed_size):\n",
    "        super().__init__()\n",
    "        self.vocab_size = vocab_size\n",
    "        self.max_len = max_len\n",
    "        self.embed_size = embed_size\n",
    "        self.word_embedding = nn.Embedding(vocab_size, embed_size)\n",
    "        self.pos_embedding = nn.Embedding(max_len, embed_size)\n",
    "        \n",
    "    def forward(self, input_ids, pos_ids):\n",
    "        \"\"\"\n",
    "        input_ids/pos_ids: batch_size * seq_len\n",
    "        return: batch_size * seq_len * embed_size\n",
    "        \"\"\"\n",
    "        word_embed = self.word_embedding(input_ids)\n",
    "        pos_embed = self.pos_embedding(pos_ids)\n",
    "        # 将词嵌入和位置嵌入相加得到嵌入层输出\n",
    "        return word_embed + pos_embed\n",
    "\n",
    "# 缩放点乘注意力\n",
    "class ScaledDotProductAttention(nn.Module):\n",
    "    def __init__(self, dropout):\n",
    "        super().__init__()\n",
    "        self.dropout = nn.Dropout(dropout)\n",
    "    \n",
    "    def forward(self, queries, keys, values, attention_mask):\n",
    "        \"\"\"\n",
    "        queries/keys/values: batch_size * seq_len * hidden_size\n",
    "        attention_mask: batch_size * seq_len * seq_len\n",
    "        return: batch_size * seq_len * hidden_size\n",
    "        \"\"\"\n",
    "        d = queries.size(-1)\n",
    "        # 根据点乘注意力的矩阵形式计算注意力分数，除以查询向量或键向量\n",
    "        # 维度的平方根，即为缩放点乘注意力\n",
    "        scores = torch.bmm(queries, torch.transpose(keys, 1, 2)) / np.sqrt(d)\n",
    "        # 将掩码为0的位置的注意力分数设为一个大负数，根据softmax函数\n",
    "        # 的性质，这些注意力分数归一化后接近0\n",
    "        scores[attention_mask == 0] = -1e6\n",
    "        self.attention_weights = F.softmax(scores, dim=-1)\n",
    "        return torch.bmm(self.dropout(self.attention_weights), values)\n",
    "    \n",
    "class MultiHeadSelfAttention(nn.Module):\n",
    "    def __init__(self, hidden_size, num_heads, dropout):\n",
    "        super().__init__()\n",
    "        assert hidden_size % num_heads == 0\n",
    "        self.hidden_size = hidden_size\n",
    "        self.num_heads = num_heads\n",
    "        self.W_q = nn.Linear(hidden_size, hidden_size)\n",
    "        self.W_k = nn.Linear(hidden_size, hidden_size)\n",
    "        self.W_v = nn.Linear(hidden_size, hidden_size)\n",
    "        self.W_o = nn.Linear(hidden_size, hidden_size)\n",
    "        self.attention = ScaledDotProductAttention(dropout)\n",
    "    \n",
    "    def transpose_qkv(self, states):\n",
    "        # 将长度为hidden_size的向量分成num_heads个长度相等的向量\n",
    "        states = states.reshape(states.shape[0], states.shape[1],\\\n",
    "            self.num_heads, self.hidden_size // self.num_heads)\n",
    "        states = torch.permute(states, (0, 2, 1, 3))\n",
    "        return states.reshape(-1, states.shape[2], states.shape[3])\n",
    "    \n",
    "    # 与transpose_qkv的变换相反\n",
    "    def transpose_output(self, states):\n",
    "        states = states.reshape(-1, self.num_heads, states.shape[1],\\\n",
    "            states.shape[2])\n",
    "        states = torch.permute(states, (0, 2, 1, 3))\n",
    "        return states.reshape(states.shape[0], states.shape[1], -1)\n",
    "    \n",
    "    def forward(self, queries, keys, values, attention_mask):\n",
    "        \"\"\"\n",
    "        querys/keys/values: batch * seq_len * hidden_size\n",
    "        attention_mask: batch * seq_len * seq_len\n",
    "        return:\n",
    "        \"\"\"\n",
    "        # (batch_size * num_heads) * seq_len * (hidden_size / num_heads)\n",
    "        queries = self.transpose_qkv(self.W_q(queries))\n",
    "        keys = self.transpose_qkv(self.W_k(keys))\n",
    "        values = self.transpose_qkv(self.W_v(values))\n",
    "        # 重复张量的元素，用以支持多个注意力头的运算\n",
    "        # (batch_size * num_heads) * seq_len * seq_len\n",
    "        attention_mask = torch.repeat_interleave(attention_mask,\\\n",
    "            repeats=self.num_heads, dim=0)\n",
    "        # (batch_size * num_heads) * seq_len * (hidden_size / num_heads)\n",
    "        output = self.attention(queries, keys, values, attention_mask)\n",
    "        # batch * seq_len * hidden_size\n",
    "        output_concat = self.transpose_output(output)\n",
    "        return self.W_o(output_concat)\n",
    "\n",
    "# 两层前馈神经网络\n",
    "class PositionWiseFNN(nn.Module):\n",
    "    def __init__(self, hidden_size, intermediate_size):\n",
    "        super().__init__()\n",
    "        self.dense1 = nn.Linear(hidden_size, intermediate_size)\n",
    "        self.relu = nn.ReLU()\n",
    "        self.dense2 = nn.Linear(intermediate_size, hidden_size)\n",
    "        \n",
    "    def forward(self, X):\n",
    "        return self.dense2(self.relu(self.dense1(X)))\n",
    "\n",
    "# 层归一化\n",
    "class LayerNorm(nn.Module):\n",
    "    def __init__(self, normalized_shape, eps=1e-6):\n",
    "        super().__init__()\n",
    "        self.gamma = nn.Parameter(torch.ones(normalized_shape))\n",
    "        self.beta = nn.Parameter(torch.zeros(normalized_shape))\n",
    "        # 一个小量用于数值稳定（防止除0）\n",
    "        self.eps = eps\n",
    "        \n",
    "    def forward(self, hidden_states):\n",
    "        mean = torch.mean(hidden_states, -1, keepdim=True)\n",
    "        std = torch.std(hidden_states, -1, keepdim=True)\n",
    "        return self.gamma * (hidden_states - mean) / (std +\\\n",
    "            self.eps) + self.beta\n",
    "\n",
    "# 将两个输入相加并归一化\n",
    "class AddNorm(nn.Module):\n",
    "    def __init__(self, hidden_size, dropout):\n",
    "        super().__init__()\n",
    "        self.dropout = nn.Dropout(dropout)\n",
    "        self.layer_norm = LayerNorm(hidden_size)\n",
    "        \n",
    "    def forward(self, X, Y):\n",
    "        return self.layer_norm(self.dropout(Y) + X)\n",
    "    \n",
    "# 一个完整的Transformer层\n",
    "class TransformerLayer(nn.Module):\n",
    "    def __init__(self, hidden_size, num_heads, dropout, intermediate_size):\n",
    "        super().__init__()\n",
    "        self.self_attention = MultiHeadSelfAttention(hidden_size,\\\n",
    "            num_heads, dropout)\n",
    "        self.add_norm1 = AddNorm(hidden_size, dropout)\n",
    "        self.fnn = PositionWiseFNN(hidden_size, intermediate_size)\n",
    "        self.add_norm2 = AddNorm(hidden_size, dropout)\n",
    "    \n",
    "    def forward(self, X, attention_mask):\n",
    "        Y = self.add_norm1(X, self.self_attention(X, X, X, attention_mask))\n",
    "        return self.add_norm2(Y, self.fnn(Y))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "2fd3f8f4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在Transformer模型基础上加上语言模型需要的输入输出、损失计算等\n",
    "class TransformerLM(nn.Module):\n",
    "    def __init__(self, vocab_size, max_len, hidden_size, num_layers,\\\n",
    "                 num_heads, dropout, intermediate_size):\n",
    "        super().__init__()\n",
    "        self.embedding_layer = EmbeddingLayer(vocab_size, max_len,\\\n",
    "            hidden_size)\n",
    "        self.num_layers = num_layers\n",
    "        # 使用ModuleList保存多个Transformer层，注意不能使用Python列表，\n",
    "        # Python列表保存的PyTorch变量无法自动求导\n",
    "        self.layers = nn.ModuleList([TransformerLayer(hidden_size,\\\n",
    "            num_heads, dropout, intermediate_size)\\\n",
    "            for _ in range(num_layers)])\n",
    "        self.output_layer = nn.Linear(hidden_size, vocab_size)\n",
    "        \n",
    "    def forward(self, input_ids):\n",
    "        # 这里实现的forward()函数一次只能处理一句话，\n",
    "        # 如果想要支持批次运算，实现起来会更复杂，也会引入冗余操作\n",
    "        seq_len = input_ids.size(0)\n",
    "        assert input_ids.ndim == 1 and seq_len <= \\\n",
    "            self.embedding_layer.max_len\n",
    "        \n",
    "        # 1 * seq_len\n",
    "        input_ids = torch.unsqueeze(input_ids, dim=0)\n",
    "        pos_ids = torch.unsqueeze(torch.arange(seq_len), dim=0)\n",
    "        # 定义下三角掩码，用于语言模型训练\n",
    "        # 1 * seq_len * seq_len\n",
    "        attention_mask = torch.unsqueeze(torch.tril(torch.ones((seq_len,\\\n",
    "            seq_len), dtype=torch.int32)), dim=0)\n",
    "        # 1 * seq_len * hidden_size\n",
    "        hidden_states = self.embedding_layer(input_ids, pos_ids)\n",
    "        for layer in self.layers:\n",
    "            hidden_states = layer(hidden_states, attention_mask)\n",
    "        outputs = self.output_layer(hidden_states)\n",
    "        \n",
    "        loss_fct = nn.CrossEntropyLoss(ignore_index=0)\n",
    "        loss = loss_fct(outputs[:, :-1].squeeze(),\\\n",
    "            input_ids[:, 1:].squeeze())\n",
    "        return loss"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "e459fc19",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-49, loss=1.5879: 100%|█| 50/50 [12:27<00:00, 14.96s/it\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 训练TransformerLM，由于不再采取批次训练，因此不再使用RNNLM和data_loader\n",
    "def train_transformer_lm(data, model, epochs=50, learning_rate=1e-3):\n",
    "    optimizer = Adam(model.parameters(), lr=learning_rate)\n",
    "    model.zero_grad()\n",
    "    model.train()\n",
    "    \n",
    "    epoch_loss = []\n",
    "    with trange(epochs, desc='epoch', ncols=60) as pbar:\n",
    "        for epoch in pbar:\n",
    "            step_loss = []\n",
    "            np.random.shuffle(data)\n",
    "            for step, x in enumerate(data):\n",
    "                loss = model(torch.tensor(x, dtype=torch.long))\n",
    "                pbar.set_description(f'epoch-{epoch},'+\\\n",
    "                    f' loss={loss.item():.4f}')\n",
    "                loss.backward()\n",
    "                grad_clipping(model)\n",
    "                optimizer.step()\n",
    "                model.zero_grad()\n",
    "                step_loss.append(loss.item())\n",
    "            # 本章前面的模型训练使用batch_size为16，\n",
    "            # TransformerLM出于简便实现只能使用batch_size为1\n",
    "            # 因此TransformerLM每一步的损失方差会更大，\n",
    "            # 为便于对比，取每个epoch最后16个样本的平均损失\n",
    "            epoch_loss.append(np.mean(step_loss[-16:]))\n",
    "    \n",
    "    epoch_loss = np.array(epoch_loss)\n",
    "    plt.plot(range(len(epoch_loss)), epoch_loss)\n",
    "    plt.xlabel('training epoch')\n",
    "    plt.ylabel('loss')\n",
    "    plt.show()\n",
    "    \n",
    "sent_tokens = dataset.convert_tokens_to_ids()\n",
    "max_len=40\n",
    "for i, tokens in enumerate(sent_tokens):\n",
    "    tokens = tokens[:max_len]\n",
    "    tokens += [0] * (max_len - len(tokens))\n",
    "    sent_tokens[i] = tokens\n",
    "sent_tokens = np.array(sent_tokens)\n",
    "\n",
    "model = TransformerLM(vocab_size, max_len=40, hidden_size=128,\\\n",
    "    num_layers=1, num_heads=4, dropout=0., intermediate_size=512)\n",
    "train_transformer_lm(sent_tokens, model)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cfb87fec",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
